1#[cfg(feature = "std")] use std::convert::{From, Into};
4#[cfg(feature = "std")] use std::ops::{Div, Rem};
5#[cfg(feature = "std")] use std::cmp::Ordering;
6
7#[cfg(not(feature = "std"))] use core::convert::{From, Into};
8#[cfg(not(feature = "std"))] use core::ops::{Div, Rem};
9#[cfg(not(feature = "std"))] use core::cmp::Ordering;
10
11use super::{Sign, M256, U256};
12
13const SIGN_BIT_MASK: M256 = M256(U256([0xffffffffffffffff, 0xffffffffffffffff,
14 0xffffffffffffffff, 0x7fffffffffffffff]));
15
16#[derive(Eq, PartialEq, Debug, Copy, Clone, Hash)]
17pub struct MI256(pub Sign, pub M256);
19
20impl MI256 {
21 pub fn zero() -> MI256 { MI256(Sign::NoSign, M256::zero()) }
23 pub fn one() -> MI256 { MI256(Sign::Plus, M256::one()) }
25 pub fn max_value() -> MI256 { MI256(Sign::Plus, M256::max_value() & SIGN_BIT_MASK) }
27 pub fn min_value() -> MI256 { MI256(Sign::Minus, (M256::max_value() & SIGN_BIT_MASK) + M256::from(1u64)) }
29}
30
31impl Default for MI256 { fn default() -> MI256 { MI256::zero() } }
32impl From<M256> for MI256 {
33 fn from(val: M256) -> MI256 {
34 if val == M256::zero() {
35 MI256::zero()
36 } else if val & SIGN_BIT_MASK.into() == val {
37 MI256(Sign::Plus, val)
38 } else {
39 MI256(Sign::Minus, !val + M256::from(1u64))
40 }
41 }
42}
43impl Into<M256> for MI256 {
44 fn into(self) -> M256 {
45 let sign = self.0;
46 if sign == Sign::NoSign {
47 M256::zero()
48 } else if sign == Sign::Plus {
49 self.1
50 } else {
51 !self.1 + M256::from(1u64)
52 }
53 }
54}
55
56impl Ord for MI256 {
57 fn cmp(&self, other: &MI256) -> Ordering {
58 match (self.0, other.0) {
59 (Sign::NoSign, Sign::NoSign) => Ordering::Equal,
60 (Sign::NoSign, Sign::Plus) => Ordering::Less,
61 (Sign::NoSign, Sign::Minus) => Ordering::Greater,
62 (Sign::Minus, Sign::NoSign) => Ordering::Less,
63 (Sign::Minus, Sign::Plus) => Ordering::Less,
64 (Sign::Minus, Sign::Minus) => self.1.cmp(&other.1).reverse(),
65 (Sign::Plus, Sign::Minus) => Ordering::Greater,
66 (Sign::Plus, Sign::NoSign) => Ordering::Greater,
67 (Sign::Plus, Sign::Plus) => self.1.cmp(&other.1),
68 }
69 }
70}
71
72impl PartialOrd for MI256 {
73 fn partial_cmp(&self, other: &MI256) -> Option<Ordering> {
74 Some(self.cmp(other))
75 }
76}
77
78impl Div for MI256 {
79 type Output = MI256;
80
81 fn div(self, other: MI256) -> MI256 {
82 if other == MI256::zero() {
83 return MI256::zero();
84 }
85
86 if self == MI256::min_value() && other == MI256(Sign::Minus, M256::from(1u64)) {
87 return MI256::min_value();
88 }
89
90 let d = (self.1 / other.1) & SIGN_BIT_MASK.into();
91
92 if d == M256::zero() {
93 return MI256::zero();
94 }
95
96 match (self.0, other.0) {
97 (Sign::Plus, Sign::Plus) |
98 (Sign::Minus, Sign::Minus) => MI256(Sign::Plus, d),
99 (Sign::Plus, Sign::Minus) |
100 (Sign::Minus, Sign::Plus) => MI256(Sign::Minus, d),
101 _ => MI256::zero()
102 }
103 }
104}
105
106impl Rem for MI256 {
107 type Output = MI256;
108
109 fn rem(self, other: MI256) -> MI256 {
110 let r = (self.1 % other.1) & SIGN_BIT_MASK.into();
111
112 if r == M256::zero() {
113 return MI256::zero()
114 }
115
116 MI256(self.0, r)
117 }
118}
119
120#[cfg(test)]
121mod tests {
122 use super::MI256;
123 use m256::M256;
124 use std::str::FromStr;
125
126 #[test]
127 pub fn sdiv() {
128 assert_eq!(MI256::from(M256::from_str("8000000000000000000000000000000000000000000000000000000000000000").unwrap()) / MI256::from(M256::from_str("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap()), MI256::from(M256::from_str("8000000000000000000000000000000000000000000000000000000000000000").unwrap()));
129 }
130
131 #[test]
132 pub fn m256() {
133 let m256 = M256::from_str("8000000000000000000000000000000000000000000000000000000000000000").unwrap();
134 let mi256 = MI256::from(m256);
135 let m256b: M256 = mi256.into();
136 assert_eq!(m256, m256b);
137 }
138}