yui_core/traits/
int_ext.rs

1use num_bigint::BigInt;
2use num_traits::{One, Signed, ToPrimitive, FromPrimitive};
3use crate::*;
4
5pub trait IntOps<T = Self>: EucRingOps<T> {}
6
7pub trait Integer: EucRing + IntOps + Signed + PartialOrd + Ord + FromPrimitive + ToPrimitive
8where for<'a> &'a Self: EucRingOps<Self> {}
9
10impl<T> DivRound for T
11where T: Integer, for<'x> &'x T: IntOps<T> {
12    fn div_round(&self, q: &Self) -> Self {
13        let a = self.to_f64().unwrap();
14        let b = q.to_f64().unwrap();
15        let r = (a / b).round();
16        Self::from_f64(r).unwrap()
17    }
18}
19
20macro_rules! impl_ops {
21    ($trait:ident, $type:ty) => {
22        impl $trait for $type {}
23        impl<'a> $trait<$type> for &'a $type {}
24    };
25}
26
27macro_rules! impl_integer {
28    ($type:ident) => {
29        impl_ops!(AddMonOps, $type);
30        impl_ops!(AddGrpOps, $type);
31        impl_ops!(MonOps, $type);
32        impl_ops!(RingOps, $type);
33        impl_ops!(EucRingOps, $type);
34        impl_ops!(IntOps, $type);
35
36        impl Elem for $type {
37            fn math_symbol() -> String { 
38                String::from("Z")
39            }
40        }
41        
42        impl AddMon for $type {}
43        impl AddGrp for $type {}
44        impl Mon for $type {}
45        impl Ring for $type {
46            fn inv(&self) -> Option<Self> {
47                if self.is_unit() { 
48                    Some(self.clone())
49                } else { 
50                    None
51                }
52            }
53        
54            fn is_unit(&self) -> bool {
55                self.is_one() || (-self).is_one()
56            }
57        
58            fn normalizing_unit(&self) -> Self {
59                if !self.is_negative() { 
60                    Self::one() 
61                } else { 
62                    -Self::one() 
63                }
64            }
65
66            fn c_weight(&self) -> f64 {
67                self.abs().to_f64().unwrap()
68            }
69        }
70
71        impl EucRing for $type {
72            fn gcd(x: &Self, y: &Self) -> Self {
73                num_integer::Integer::gcd(x, y)
74            }
75
76            fn gcdx(x: &Self, y: &Self) -> (Self, Self, Self) {
77                let num_integer::ExtendedGcd{ gcd: d, x: s, y: t } = num_integer::Integer::extended_gcd(x, y);
78                (d, s, t)
79            }
80
81            fn lcm(x: &Self, y: &Self) -> Self {
82                num_integer::Integer::lcm(x, y)
83            }
84        }
85
86        impl Integer for $type {}
87    }
88}
89
90impl_integer!(i32);
91impl_integer!(i64);
92impl_integer!(i128);
93impl_integer!(BigInt);
94
95#[cfg(feature = "tex")] 
96mod tex {
97    use crate::tex::TeX;
98    use num_bigint::BigInt;
99
100    macro_rules! impl_tex {
101        ($type:ident) => {
102            impl TeX for $type {
103                fn tex_math_symbol() -> String { 
104                    String::from("\\mathbb{Z}")
105                }
106                fn tex_string(&self) -> String {
107                    self.to_string()
108                }
109            }
110        }
111    }
112
113    impl_tex!(i32);
114    impl_tex!(i64);
115    impl_tex!(i128);
116    impl_tex!(BigInt);        
117}
118
119#[cfg(test)]
120mod tests { 
121    use super::*;
122
123    #[test]
124    fn check_type() {
125        fn check<T>() where T: Integer, for<'a> &'a T: IntOps<T> {}
126        check::<i32>();
127        check::<i64>();
128        check::<i128>();
129        check::<BigInt>();
130    }
131
132    #[test]
133    fn int_is_unit() { 
134        assert!(1.is_unit());
135        assert!((-1).is_unit());
136        assert!(!2.is_unit());
137    }
138
139    #[test]
140    fn int_inv() { 
141        assert_eq!(1.inv(), Some(1));
142        assert_eq!((-1).inv(), Some(-1));
143        assert_eq!(2.inv(), None);
144    }
145
146    #[test]
147    fn int_normalizing_unit() { 
148        assert_eq!(1.normalizing_unit(), 1);
149        assert_eq!((-1).normalizing_unit(), -1);
150        assert_eq!(2.normalizing_unit(), 1);
151    }
152
153    #[test]
154    fn int_divides() {
155        assert!(2.divides(&4));
156        assert!(!3.divides(&4));
157        assert!(!0.divides(&1));
158    }
159
160    #[test]
161    fn gcd_i32() {
162        let (a, b) = (240, 46);
163        let d = i32::gcd(&a, &b);
164        assert_eq!(d, 2);
165
166        let (a, b) = (24, 0);
167        let d = i32::gcd(&a, &b);
168        assert_eq!(d, 24);
169
170        let (a, b) = (0, -24);
171        let d = i32::gcd(&a, &b);
172        assert_eq!(d, 24);
173
174        let (a, b) = (0, 0);
175        let d = i32::gcd(&a, &b);
176        assert_eq!(d, 0);
177    }
178
179    #[test]
180    fn gcdx_i32() {
181        let (a, b) = (240, 46);
182        let (d, s, t) = i32::gcdx(&a, &b);
183        assert_eq!(d, 2);
184        assert_eq!(s * a + t * b, d);
185
186        let (a, b) = (24, 0);
187        let (d, s, t) = i32::gcdx(&a, &b);
188        assert_eq!(d, 24);
189        assert_eq!(s * a + t * b, d);
190
191        let (a, b) = (0, 0);
192        let (d, s, t) = i32::gcdx(&a, &b);
193        assert_eq!(d, 0);
194        assert_eq!(s * a + t * b, d);
195    }
196
197    #[test]
198    fn div_round() { 
199        assert_eq!(12.div_round(&5), 2);
200        assert_eq!(13.div_round(&5), 3);
201        assert_eq!((-12).div_round(&5), -2);
202        assert_eq!((-13).div_round(&5), -3);
203    }
204
205    #[cfg(feature = "tex")]
206    #[test]
207    fn tex() { 
208        use crate::tex::*;
209        assert_eq!(i32::tex_math_symbol(), "\\mathbb{Z}");
210        assert_eq!((-2).tex_string(), "-2");
211    }
212}