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