qfall_math/integer/z/
gcd.rs1use super::Z;
13use crate::traits::{Gcd, Xgcd};
14use flint_sys::fmpz::{fmpz_gcd, fmpz_xgcd};
15
16impl<Integer: Into<Z>> Gcd<Integer> for Z {
17 type Output = Z;
18
19 fn gcd(&self, other: Integer) -> Self::Output {
41 let other = other.into();
42 let mut out = Z::default();
43 unsafe { fmpz_gcd(&mut out.value, &self.value, &other.value) };
44 out
45 }
46}
47
48impl<Integer: Into<Z>> Xgcd<Integer> for Z {
49 type Output = (Z, Z, Z);
50
51 fn xgcd(&self, other: Integer) -> Self::Output {
75 let other = other.into();
76 let mut gcd = Z::ZERO;
77 let mut x = Z::ZERO;
78 let mut y = Z::ZERO;
79 unsafe {
80 fmpz_xgcd(
81 &mut gcd.value,
82 &mut x.value,
83 &mut y.value,
84 &self.value,
85 &other.value,
86 )
87 };
88 (gcd, x, y)
89 }
90}
91
92#[cfg(test)]
93mod test_gcd {
94 use super::{Gcd, Z};
95
96 #[test]
99 fn small() {
100 let pos_1 = Z::from(10);
101 let pos_2 = Z::from(15);
102 let neg_1 = Z::from(-10);
103 let neg_2 = Z::from(-15);
104
105 let gcd_pos_1 = pos_1.gcd(&pos_2);
106 let gcd_pos_2 = pos_2.gcd(&pos_1);
107 let gcd_pos_eq = pos_1.gcd(&pos_1);
108 let gcd_mix_1 = pos_1.gcd(&neg_1);
109 let gcd_mix_2 = neg_2.gcd(&pos_1);
110 let gcd_neg_1 = neg_1.gcd(&neg_2);
111 let gcd_neg_2 = neg_2.gcd(&neg_1);
112 let gcd_neg_eq = neg_2.gcd(&neg_2);
113
114 assert_eq!(Z::from(5), gcd_pos_1);
115 assert_eq!(Z::from(5), gcd_pos_2);
116 assert_eq!(Z::from(10), gcd_pos_eq);
117 assert_eq!(Z::from(10), gcd_mix_1);
118 assert_eq!(Z::from(5), gcd_mix_2);
119 assert_eq!(Z::from(5), gcd_neg_1);
120 assert_eq!(Z::from(5), gcd_neg_2);
121 assert_eq!(Z::from(15), gcd_neg_eq);
122 }
123
124 #[test]
128 fn large() {
129 let pos = Z::from(i64::MAX);
130 let zero = Z::ZERO;
131 let neg = Z::from(i64::MIN);
132 let abs_neg = Z::MINUS_ONE * &neg;
133
134 let gcd_1 = pos.gcd(&zero);
135 let gcd_2 = pos.gcd(&pos);
136 let gcd_3 = neg.gcd(&zero);
137 let gcd_4 = neg.gcd(&neg);
138 let gcd_5 = pos.gcd(&neg);
139
140 assert_eq!(pos, gcd_1);
141 assert_eq!(pos, gcd_2);
142 assert_eq!(abs_neg, gcd_3);
143 assert_eq!(abs_neg, gcd_4);
144 assert_eq!(Z::ONE, gcd_5);
145 }
146
147 #[test]
149 fn availability() {
150 let z = Z::ONE;
151
152 let _ = z.gcd(z.clone());
153 let _ = z.gcd(4_u8);
154 let _ = z.gcd(4_u16);
155 let _ = z.gcd(4_u32);
156 let _ = z.gcd(4_u64);
157 let _ = z.gcd(4_i8);
158 let _ = z.gcd(4_i16);
159 let _ = z.gcd(4_i32);
160 let _ = z.gcd(4_i64);
161 }
162}
163
164#[cfg(test)]
165mod test_xgcd {
166 use super::{Xgcd, Z};
167
168 #[test]
171 fn gcd_small() {
172 let pos_1 = Z::from(10);
173 let pos_2 = Z::from(15);
174 let neg_1 = Z::from(-10);
175 let neg_2 = Z::from(-15);
176
177 let xgcd_pos_1 = pos_1.xgcd(&pos_2);
178 let xgcd_pos_2 = pos_2.xgcd(&pos_1);
179 let xgcd_pos_eq = pos_1.xgcd(&pos_1);
180 let xgcd_mix_1 = pos_1.xgcd(&neg_1);
181 let xgcd_mix_2 = neg_2.xgcd(&pos_1);
182 let xgcd_neg_1 = neg_1.xgcd(&neg_2);
183 let xgcd_neg_2 = neg_2.xgcd(&neg_1);
184 let xgcd_neg_eq = neg_2.xgcd(&neg_2);
185
186 assert_eq!(Z::from(5), xgcd_pos_1.0);
187 assert_eq!(Z::from(5), xgcd_pos_2.0);
188 assert_eq!(Z::from(10), xgcd_pos_eq.0);
189 assert_eq!(Z::from(10), xgcd_mix_1.0);
190 assert_eq!(Z::from(5), xgcd_mix_2.0);
191 assert_eq!(Z::from(5), xgcd_neg_1.0);
192 assert_eq!(Z::from(5), xgcd_neg_2.0);
193 assert_eq!(Z::from(15), xgcd_neg_eq.0);
194 }
195
196 #[test]
200 fn gcd_large() {
201 let pos = Z::from(i64::MAX);
202 let zero = Z::ZERO;
203 let neg = Z::from(i64::MIN);
204 let abs_neg = Z::MINUS_ONE * &neg;
205
206 let xgcd_1 = pos.xgcd(&zero);
207 let xgcd_2 = pos.xgcd(&pos);
208 let xgcd_3 = neg.xgcd(&zero);
209 let xgcd_4 = neg.xgcd(&neg);
210 let xgcd_5 = pos.xgcd(&neg);
211
212 assert_eq!(pos, xgcd_1.0);
213 assert_eq!(pos, xgcd_2.0);
214 assert_eq!(abs_neg, xgcd_3.0);
215 assert_eq!(abs_neg, xgcd_4.0);
216 assert_eq!(Z::ONE, xgcd_5.0);
217 }
218
219 #[test]
222 fn xy_small() {
223 let pos_1 = Z::from(10);
224 let pos_2 = Z::from(15);
225 let neg_1 = Z::from(-10);
226 let neg_2 = Z::from(-15);
227
228 let xgcd_pos_1 = pos_1.xgcd(&pos_2);
229 let xgcd_pos_2 = pos_2.xgcd(&pos_1);
230 let xgcd_pos_eq = pos_1.xgcd(&pos_1);
231 let xgcd_mix_1 = pos_1.xgcd(&neg_1);
232 let xgcd_mix_2 = neg_2.xgcd(&pos_1);
233 let xgcd_neg_1 = neg_1.xgcd(&neg_2);
234 let xgcd_neg_2 = neg_2.xgcd(&neg_1);
235 let xgcd_neg_eq = neg_2.xgcd(&neg_2);
236
237 assert_eq!(
239 xgcd_pos_1.0,
240 &pos_1 * &xgcd_pos_1.1 + &pos_2 * &xgcd_pos_1.2
241 );
242 assert_eq!(
243 xgcd_pos_2.0,
244 &pos_2 * &xgcd_pos_2.1 + &pos_1 * &xgcd_pos_2.2
245 );
246 assert_eq!(
247 xgcd_pos_eq.0,
248 &pos_1 * &xgcd_pos_eq.1 + &pos_1 * &xgcd_pos_eq.2
249 );
250 assert_eq!(
251 xgcd_mix_1.0,
252 &pos_1 * &xgcd_mix_1.1 + &neg_1 * &xgcd_mix_1.2
253 );
254 assert_eq!(
255 xgcd_mix_2.0,
256 &neg_2 * &xgcd_mix_2.1 + &pos_1 * &xgcd_mix_2.2
257 );
258 assert_eq!(
259 xgcd_neg_1.0,
260 &neg_1 * &xgcd_neg_1.1 + &neg_2 * &xgcd_neg_1.2
261 );
262 assert_eq!(
263 xgcd_neg_2.0,
264 &neg_2 * &xgcd_neg_2.1 + &neg_1 * &xgcd_neg_2.2
265 );
266 assert_eq!(
267 xgcd_neg_eq.0,
268 &neg_2 * &xgcd_neg_eq.1 + &neg_2 * &xgcd_neg_eq.2
269 );
270 }
271
272 #[test]
275 fn xy_large() {
276 let pos = Z::from(i64::MAX);
277 let zero = Z::ZERO;
278 let neg = Z::from(i64::MIN);
279
280 let xgcd_1 = pos.xgcd(&zero);
281 let xgcd_2 = pos.xgcd(&pos);
282 let xgcd_3 = neg.xgcd(&zero);
283 let xgcd_4 = neg.xgcd(&neg);
284 let xgcd_5 = pos.xgcd(&neg);
285
286 assert_eq!(xgcd_1.0, &pos * &xgcd_1.1 + &zero * &xgcd_1.2);
288 assert_eq!(xgcd_2.0, &pos * &xgcd_2.1 + &pos * &xgcd_2.2);
289 assert_eq!(xgcd_3.0, &neg * &xgcd_3.1 + &zero * &xgcd_3.2);
290 assert_eq!(xgcd_4.0, &neg * &xgcd_4.1 + &neg * &xgcd_4.2);
291 assert_eq!(xgcd_5.0, &pos * &xgcd_5.1 + &neg * &xgcd_5.2);
292 }
293
294 #[test]
296 fn availability() {
297 let z = Z::ONE;
298
299 let _ = z.xgcd(z.clone());
300 let _ = z.xgcd(4_u8);
301 let _ = z.xgcd(4_u16);
302 let _ = z.xgcd(4_u32);
303 let _ = z.xgcd(4_u64);
304 let _ = z.xgcd(4_i8);
305 let _ = z.xgcd(4_i16);
306 let _ = z.xgcd(4_i32);
307 let _ = z.xgcd(4_i64);
308 }
309}