yui_core/traits/
int_ext.rs1use 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}