1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
use core::ops::{Rem, Div};
use core::cmp::Ordering;
use primitive_types::U256;
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub enum Sign {
Plus,
Minus,
NoSign,
}
const SIGN_BIT_MASK: U256 = U256([0xffffffffffffffff, 0xffffffffffffffff,
0xffffffffffffffff, 0x7fffffffffffffff]);
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub struct I256(pub Sign, pub U256);
impl I256 {
pub fn zero() -> I256 { I256(Sign::NoSign, U256::zero()) }
pub fn min_value() -> I256 { I256(Sign::Minus, (U256::max_value() & SIGN_BIT_MASK) + U256::from(1u64)) }
}
impl Ord for I256 {
fn cmp(&self, other: &I256) -> Ordering {
match (self.0, other.0) {
(Sign::NoSign, Sign::NoSign) => Ordering::Equal,
(Sign::NoSign, Sign::Plus) => Ordering::Less,
(Sign::NoSign, Sign::Minus) => Ordering::Greater,
(Sign::Minus, Sign::NoSign) => Ordering::Less,
(Sign::Minus, Sign::Plus) => Ordering::Less,
(Sign::Minus, Sign::Minus) => self.1.cmp(&other.1).reverse(),
(Sign::Plus, Sign::Minus) => Ordering::Greater,
(Sign::Plus, Sign::NoSign) => Ordering::Greater,
(Sign::Plus, Sign::Plus) => self.1.cmp(&other.1),
}
}
}
impl PartialOrd for I256 {
fn partial_cmp(&self, other: &I256) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Default for I256 { fn default() -> I256 { I256::zero() } }
impl From<U256> for I256 {
fn from(val: U256) -> I256 {
if val == U256::zero() {
I256::zero()
} else if val & SIGN_BIT_MASK.into() == val {
I256(Sign::Plus, val)
} else {
I256(Sign::Minus, !val + U256::from(1u64))
}
}
}
impl Into<U256> for I256 {
fn into(self) -> U256 {
let sign = self.0;
if sign == Sign::NoSign {
U256::zero()
} else if sign == Sign::Plus {
self.1
} else {
!self.1 + U256::from(1u64)
}
}
}
impl Div for I256 {
type Output = I256;
fn div(self, other: I256) -> I256 {
if other == I256::zero() {
return I256::zero();
}
if self == I256::min_value() && other == I256(Sign::Minus, U256::from(1u64)) {
return I256::min_value();
}
let d = (self.1 / other.1) & SIGN_BIT_MASK.into();
if d == U256::zero() {
return I256::zero();
}
match (self.0, other.0) {
(Sign::Plus, Sign::Plus) |
(Sign::Minus, Sign::Minus) => I256(Sign::Plus, d),
(Sign::Plus, Sign::Minus) |
(Sign::Minus, Sign::Plus) => I256(Sign::Minus, d),
_ => I256::zero()
}
}
}
impl Rem for I256 {
type Output = I256;
fn rem(self, other: I256) -> I256 {
let r = (self.1 % other.1) & SIGN_BIT_MASK.into();
if r == U256::zero() {
return I256::zero()
}
I256(self.0, r)
}
}