bigint/
mi256.rs

1//! Signed modulo 256-bit integer
2
3#[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)]
17/// Represents a signed module 256-bit integer.
18pub struct MI256(pub Sign, pub M256);
19
20impl MI256 {
21    /// Zero value of MI256.
22    pub fn zero() -> MI256 { MI256(Sign::NoSign, M256::zero()) }
23    /// One value of MI256.
24    pub fn one() -> MI256 { MI256(Sign::Plus, M256::one()) }
25    /// Maximum value of MI256.
26    pub fn max_value() -> MI256 { MI256(Sign::Plus, M256::max_value() & SIGN_BIT_MASK) }
27    /// Minimum value of MI256.
28    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}