1use crate::{udouble, Reducer, Vanilla};
4use crate::{DivExact, ModularAbs, ModularCoreOps, ModularPow, ModularSymbols, ModularUnaryOps};
5
6macro_rules! impl_core_ops_uu {
9 ($($T:ty => $Tdouble:ty;)*) => ($(
10 impl ModularCoreOps<$T, &$T> for $T {
11 type Output = $T;
12 #[inline(always)]
13 fn addm(self, rhs: $T, m: &$T) -> $T {
14 (((self as $Tdouble) + (rhs as $Tdouble)) % (*m as $Tdouble)) as $T
15 }
16 #[inline]
17 fn subm(self, rhs: $T, m: &$T) -> $T {
18 if self >= rhs {
19 (self - rhs) % m
20 } else {
21 ((rhs - self) % m).negm(m)
22 }
23 }
24 #[inline(always)]
25 fn mulm(self, rhs: $T, m: &$T) -> $T {
26 (((self as $Tdouble) * (rhs as $Tdouble)) % (*m as $Tdouble)) as $T
27 }
28 }
29 )*);
30}
31impl_core_ops_uu! { u8 => u16; u16 => u32; u32 => u64; u64 => u128; }
32
33#[cfg(target_pointer_width = "16")]
34impl_core_ops_uu! { usize => u32; }
35#[cfg(target_pointer_width = "32")]
36impl_core_ops_uu! { usize => u64; }
37#[cfg(target_pointer_width = "64")]
38impl_core_ops_uu! { usize => u128; }
39
40impl ModularCoreOps<u128, &u128> for u128 {
41 type Output = u128;
42
43 #[inline]
44 fn addm(self, rhs: u128, m: &u128) -> u128 {
45 if let Some(ab) = self.checked_add(rhs) {
46 ab % m
47 } else {
48 udouble::widening_add(self, rhs) % *m
49 }
50 }
51
52 #[inline]
53 fn subm(self, rhs: u128, m: &u128) -> u128 {
54 if self >= rhs {
55 (self - rhs) % m
56 } else {
57 ((rhs - self) % m).negm(m)
58 }
59 }
60
61 #[inline]
62 fn mulm(self, rhs: u128, m: &u128) -> u128 {
63 if let Some(ab) = self.checked_mul(rhs) {
64 ab % m
65 } else {
66 udouble::widening_mul(self, rhs) % *m
67 }
68 }
69}
70
71macro_rules! impl_powm_uprim {
72 ($($T:ty)*) => ($(
73 impl ModularPow<$T, &$T> for $T {
74 type Output = $T;
75 #[inline(always)]
76 fn powm(self, exp: $T, m: &$T) -> $T {
77 Vanilla::<$T>::new(&m).pow(self % m, &exp)
78 }
79 }
80 )*);
81}
82impl_powm_uprim!(u8 u16 u32 u64 u128 usize);
83
84macro_rules! impl_symbols_uprim {
85 ($($T:ty)*) => ($(
86 impl ModularSymbols<&$T> for $T {
87 #[inline]
88 fn checked_legendre(&self, n: &$T) -> Option<i8> {
89 match self.powm((n - 1)/2, &n) {
90 0 => Some(0),
91 1 => Some(1),
92 x if x == n - 1 => Some(-1),
93 _ => None,
94 }
95 }
96
97 fn checked_jacobi(&self, n: &$T) -> Option<i8> {
98 if n % 2 == 0 {
99 return None;
100 }
101 if self == &0 {
102 return Some(if n == &1 {
103 1
104 } else {
105 0
106 });
107 }
108 if self == &1 {
109 return Some(1);
110 }
111
112 let mut a = self % n;
113 let mut n = *n;
114 let mut t = 1;
115 while a > 0 {
116 while a % 2 == 0 {
117 a /= 2;
118 if n % 8 == 3 || n % 8 == 5 {
119 t *= -1;
120 }
121 }
122 core::mem::swap(&mut a, &mut n);
123 if a % 4 == 3 && n % 4 == 3 {
124 t *= -1;
125 }
126 a %= n;
127 }
128 Some(if n == 1 {
129 t
130 } else {
131 0
132 })
133 }
134
135 fn kronecker(&self, n: &$T) -> i8 {
136 match n {
137 0 => {
138 if self == &1 {
139 1
140 } else {
141 0
142 }
143 }
144 1 => 1,
145 2 => {
146 if self % 2 == 0 {
147 0
148 } else if self % 8 == 1 || self % 8 == 7 {
149 1
150 } else {
151 -1
152 }
153 }
154 _ => {
155 let f = n.trailing_zeros();
156 let n = n >> f;
157 self.kronecker(&2).pow(f)
158 * self.jacobi(&n)
159 }
160 }
161 }
162 }
163 )*);
164}
165impl_symbols_uprim!(u8 u16 u32 u64 u128 usize);
166
167macro_rules! impl_symbols_iprim {
168 ($($T:ty, $U:ty;)*) => ($(
169 impl ModularSymbols<&$T> for $T {
170 #[inline]
171 fn checked_legendre(&self, n: &$T) -> Option<i8> {
172 if n < &1 {
173 return None;
174 }
175 let a = self.rem_euclid(*n) as $U;
176 a.checked_legendre(&(*n as $U))
177 }
178
179 #[inline]
180 fn checked_jacobi(&self, n: &$T) -> Option<i8> {
181 if n < &1 {
182 return None;
183 }
184 let a = self.rem_euclid(*n) as $U;
185 a.checked_jacobi(&(*n as $U))
186 }
187
188 #[inline]
189 fn kronecker(&self, n: &$T) -> i8 {
190 match n {
191 -1 => {
192 if self < &0 {
193 -1
194 } else {
195 1
196 }
197 }
198 0 => {
199 if self == &1 {
200 1
201 } else {
202 0
203 }
204 }
205 1 => 1,
206 2 => {
207 if self % 2 == 0 {
208 0
209 } else if self.rem_euclid(8) == 1 || self.rem_euclid(8) == 7 {
210 1
211 } else {
212 -1
213 }
214 },
215 i if i < &-1 => {
216 self.kronecker(&-1) * self.kronecker(&-i)
217 },
218 _ => {
219 let f = n.trailing_zeros();
220 self.kronecker(&2).pow(f)
221 * self.jacobi(&(n >> f))
222 }
223 }
224 }
225 }
226 )*);
227}
228
229impl_symbols_iprim!(i8, u8; i16, u16; i32, u32; i64, u64; i128, u128; isize, usize;);
230
231macro_rules! impl_unary_uprim {
232 ($($T:ty)*) => ($(
233 impl ModularUnaryOps<&$T> for $T {
234 type Output = $T;
235 #[inline]
236 fn negm(self, m: &$T) -> $T {
237 let x = self % m;
238 if x == 0 {
239 0
240 } else {
241 m - x
242 }
243 }
244
245 fn invm(self, m: &$T) -> Option<$T> {
247 let x = if &self >= m { self % m } else { self.clone() };
249
250 let (mut last_r, mut r) = (m.clone(), x);
251 let (mut last_t, mut t) = (0, 1);
252
253 while r > 0 {
254 let (quo, rem) = (last_r / r, last_r % r);
255 last_r = r;
256 r = rem;
257
258 let new_t = last_t.subm(quo.mulm(t, m), m);
259 last_t = t;
260 t = new_t;
261 }
262
263 if last_r > 1 {
265 None
266 } else {
267 Some(last_t)
268 }
269 }
270
271 #[inline(always)]
272 fn dblm(self, m: &$T) -> $T {
273 self.addm(self, m)
274 }
275 #[inline(always)]
276 fn sqm(self, m: &$T) -> $T {
277 self.mulm(self, m)
278 }
279 }
280 )*);
281}
282impl_unary_uprim!(u8 u16 u32 u64 u128 usize);
283
284macro_rules! impl_mod_ops_by_deref {
286 ($($T:ty)*) => {$(
287 impl ModularCoreOps<$T, &$T> for &$T {
289 type Output = $T;
290 #[inline]
291 fn addm(self, rhs: $T, m: &$T) -> $T {
292 (*self).addm(rhs, &m)
293 }
294 #[inline]
295 fn subm(self, rhs: $T, m: &$T) -> $T {
296 (*self).subm(rhs, &m)
297 }
298 #[inline]
299 fn mulm(self, rhs: $T, m: &$T) -> $T {
300 (*self).mulm(rhs, &m)
301 }
302 }
303 impl ModularCoreOps<&$T, &$T> for $T {
304 type Output = $T;
305 #[inline]
306 fn addm(self, rhs: &$T, m: &$T) -> $T {
307 self.addm(*rhs, &m)
308 }
309 #[inline]
310 fn subm(self, rhs: &$T, m: &$T) -> $T {
311 self.subm(*rhs, &m)
312 }
313 #[inline]
314 fn mulm(self, rhs: &$T, m: &$T) -> $T {
315 self.mulm(*rhs, &m)
316 }
317 }
318 impl ModularCoreOps<&$T, &$T> for &$T {
319 type Output = $T;
320 #[inline]
321 fn addm(self, rhs: &$T, m: &$T) -> $T {
322 (*self).addm(*rhs, &m)
323 }
324 #[inline]
325 fn subm(self, rhs: &$T, m: &$T) -> $T {
326 (*self).subm(*rhs, &m)
327 }
328 #[inline]
329 fn mulm(self, rhs: &$T, m: &$T) -> $T {
330 (*self).mulm(*rhs, &m)
331 }
332 }
333
334 impl ModularPow<$T, &$T> for &$T {
336 type Output = $T;
337 #[inline]
338 fn powm(self, exp: $T, m: &$T) -> $T {
339 (*self).powm(exp, &m)
340 }
341 }
342 impl ModularPow<&$T, &$T> for $T {
343 type Output = $T;
344 #[inline]
345 fn powm(self, exp: &$T, m: &$T) -> $T {
346 self.powm(*exp, &m)
347 }
348 }
349 impl ModularPow<&$T, &$T> for &$T {
350 type Output = $T;
351 #[inline]
352 fn powm(self, exp: &$T, m: &$T) -> $T {
353 (*self).powm(*exp, &m)
354 }
355 }
356
357 impl ModularUnaryOps<&$T> for &$T {
359 type Output = $T;
360
361 #[inline]
362 fn negm(self, m: &$T) -> $T {
363 ModularUnaryOps::<&$T>::negm(*self, m)
364 }
365 #[inline]
366 fn invm(self, m: &$T) -> Option<$T> {
367 ModularUnaryOps::<&$T>::invm(*self, m)
368 }
369 #[inline]
370 fn dblm(self, m: &$T) -> $T {
371 ModularUnaryOps::<&$T>::dblm(*self, m)
372 }
373 #[inline]
374 fn sqm(self, m: &$T) -> $T {
375 ModularUnaryOps::<&$T>::sqm(*self, m)
376 }
377 }
378 )*};
379}
380
381impl_mod_ops_by_deref!(u8 u16 u32 u64 u128 usize);
382
383macro_rules! impl_absm_for_prim {
384 ($($signed:ty => $unsigned:ty;)*) => {$(
385 impl ModularAbs<$unsigned> for $signed {
386 fn absm(self, m: &$unsigned) -> $unsigned {
387 if self >= 0 {
388 (self as $unsigned) % m
389 } else {
390 (-self as $unsigned).negm(m)
391 }
392 }
393 }
394 )*};
395}
396
397impl_absm_for_prim! {
398 i8 => u8; i16 => u16; i32 => u32; i64 => u64; i128 => u128; isize => usize;
399}
400
401macro_rules! impl_div_exact_for_prim {
402 ($($t:ty)*) => {$(
403 impl DivExact<$t, ()> for $t {
404 type Output = $t;
405 #[inline]
406 fn div_exact(self, d: $t, _: &()) -> Option<Self::Output> {
407 let (q, r) = (self / d, self % d);
408 if r == 0 {
409 Some(q)
410 } else {
411 None
412 }
413 }
414 }
415 )*};
416}
417
418impl_div_exact_for_prim!(u8 u16 u32 u64 u128);
419
420#[cfg(test)]
421mod tests {
422 use super::*;
423 use core::ops::Neg;
424 use rand::random;
425
426 const NRANDOM: u32 = 10; #[test]
429 fn addm_test() {
430 const CASES: [(u8, u8, u8, u8); 10] = [
432 (5, 0, 0, 0),
434 (5, 1, 2, 3),
435 (5, 2, 1, 3),
436 (5, 2, 2, 4),
437 (5, 3, 2, 0),
438 (5, 2, 3, 0),
439 (5, 6, 1, 2),
440 (5, 1, 6, 2),
441 (5, 11, 7, 3),
442 (5, 7, 11, 3),
443 ];
444
445 for &(m, x, y, r) in CASES.iter() {
446 assert_eq!(x.addm(y, &m), r);
447 assert_eq!((x as u16).addm(y as u16, &(m as _)), r as _);
448 assert_eq!((x as u32).addm(y as u32, &(m as _)), r as _);
449 assert_eq!((x as u64).addm(y as u64, &(m as _)), r as _);
450 assert_eq!((x as u128).addm(y as u128, &(m as _)), r as _);
451 }
452
453 for _ in 0..NRANDOM {
455 let a = random::<u32>() as u64;
456 let b = random::<u32>() as u64;
457 let m = random::<u32>() as u64;
458 assert_eq!(a.addm(b, &m), (a + b) % m);
459 assert_eq!(
460 a.addm(b, &(1u64 << 32)) as u32,
461 (a as u32).wrapping_add(b as u32)
462 );
463
464 let a = random::<u64>() as u128;
465 let b = random::<u64>() as u128;
466 let m = random::<u64>() as u128;
467 assert_eq!(a.addm(b, &m), (a + b) % m);
468 assert_eq!(
469 a.addm(b, &(1u128 << 64)) as u64,
470 (a as u64).wrapping_add(b as u64)
471 );
472 }
473 }
474
475 #[test]
476 fn subm_test() {
477 const CASES: [(u8, u8, u8, u8); 10] = [
479 (7, 0, 0, 0),
481 (7, 11, 9, 2),
482 (7, 5, 2, 3),
483 (7, 2, 5, 4),
484 (7, 6, 7, 6),
485 (7, 1, 7, 1),
486 (7, 7, 1, 6),
487 (7, 0, 6, 1),
488 (7, 15, 1, 0),
489 (7, 1, 15, 0),
490 ];
491
492 for &(m, x, y, r) in CASES.iter() {
493 assert_eq!(x.subm(y, &m), r);
494 assert_eq!((x as u16).subm(y as u16, &(m as _)), r as _);
495 assert_eq!((x as u32).subm(y as u32, &(m as _)), r as _);
496 assert_eq!((x as u64).subm(y as u64, &(m as _)), r as _);
497 assert_eq!((x as u128).subm(y as u128, &(m as _)), r as _);
498 }
499
500 for _ in 0..NRANDOM {
502 let a = random::<u32>() as u64;
503 let b = random::<u32>() as u64;
504 let m = random::<u32>() as u64;
505 assert_eq!(
506 a.subm(b, &m),
507 (a as i64 - b as i64).rem_euclid(m as i64) as u64
508 );
509 assert_eq!(
510 a.subm(b, &(1u64 << 32)) as u32,
511 (a as u32).wrapping_sub(b as u32)
512 );
513
514 let a = random::<u64>() as u128;
515 let b = random::<u64>() as u128;
516 let m = random::<u64>() as u128;
517 assert_eq!(
518 a.subm(b, &m),
519 (a as i128 - b as i128).rem_euclid(m as i128) as u128
520 );
521 assert_eq!(
522 a.subm(b, &(1u128 << 64)) as u64,
523 (a as u64).wrapping_sub(b as u64)
524 );
525 }
526 }
527
528 #[test]
529 fn negm_and_absm_test() {
530 const CASES: [(u8, u8, u8); 5] = [
532 (5, 0, 0),
534 (5, 2, 3),
535 (5, 1, 4),
536 (5, 5, 0),
537 (5, 12, 3),
538 ];
539
540 for &(m, x, r) in CASES.iter() {
541 assert_eq!(x.negm(&m), r);
542 assert_eq!((x as i8).neg().absm(&m), r);
543 assert_eq!((x as u16).negm(&(m as _)), r as _);
544 assert_eq!((x as i16).neg().absm(&(m as u16)), r as _);
545 assert_eq!((x as u32).negm(&(m as _)), r as _);
546 assert_eq!((x as i32).neg().absm(&(m as u32)), r as _);
547 assert_eq!((x as u64).negm(&(m as _)), r as _);
548 assert_eq!((x as i64).neg().absm(&(m as u64)), r as _);
549 assert_eq!((x as u128).negm(&(m as _)), r as _);
550 assert_eq!((x as i128).neg().absm(&(m as u128)), r as _);
551 }
552
553 for _ in 0..NRANDOM {
555 let a = random::<u32>() as u64;
556 let m = random::<u32>() as u64;
557 assert_eq!(a.negm(&m), (a as i64).neg().rem_euclid(m as i64) as u64);
558 assert_eq!(a.negm(&(1u64 << 32)) as u32, (a as u32).wrapping_neg());
559
560 let a = random::<u64>() as u128;
561 let m = random::<u64>() as u128;
562 assert_eq!(a.negm(&m), (a as i128).neg().rem_euclid(m as i128) as u128);
563 assert_eq!(a.negm(&(1u128 << 64)) as u64, (a as u64).wrapping_neg());
564 }
565 }
566
567 #[test]
568 fn mulm_test() {
569 const CASES: [(u8, u8, u8, u8); 10] = [
571 (7, 0, 0, 0),
573 (7, 11, 9, 1),
574 (7, 5, 2, 3),
575 (7, 2, 5, 3),
576 (7, 6, 7, 0),
577 (7, 1, 7, 0),
578 (7, 7, 1, 0),
579 (7, 0, 6, 0),
580 (7, 15, 1, 1),
581 (7, 1, 15, 1),
582 ];
583
584 for &(m, x, y, r) in CASES.iter() {
585 assert_eq!(x.mulm(y, &m), r);
586 assert_eq!((x as u16).mulm(y as u16, &(m as _)), r as _);
587 assert_eq!((x as u32).mulm(y as u32, &(m as _)), r as _);
588 assert_eq!((x as u64).mulm(y as u64, &(m as _)), r as _);
589 assert_eq!((x as u128).mulm(y as u128, &(m as _)), r as _);
590 }
591
592 for _ in 0..NRANDOM {
594 let a = random::<u32>() as u64;
595 let b = random::<u32>() as u64;
596 let m = random::<u32>() as u64;
597 assert_eq!(a.mulm(b, &m), (a * b) % m);
598 assert_eq!(
599 a.mulm(b, &(1u64 << 32)) as u32,
600 (a as u32).wrapping_mul(b as u32)
601 );
602
603 let a = random::<u64>() as u128;
604 let b = random::<u64>() as u128;
605 let m = random::<u64>() as u128;
606 assert_eq!(a.mulm(b, &m), (a * b) % m);
607 assert_eq!(
608 a.mulm(b, &(1u128 << 32)) as u32,
609 (a as u32).wrapping_mul(b as u32)
610 );
611 }
612 }
613
614 #[test]
615 fn powm_test() {
616 const CASES: [(u8, u8, u8, u8); 12] = [
618 (7, 0, 0, 1),
620 (7, 11, 9, 1),
621 (7, 5, 2, 4),
622 (7, 2, 5, 4),
623 (7, 6, 7, 6),
624 (7, 1, 7, 1),
625 (7, 7, 1, 0),
626 (7, 0, 6, 0),
627 (7, 15, 1, 1),
628 (7, 1, 15, 1),
629 (7, 255, 255, 6),
630 (10, 255, 255, 5),
631 ];
632
633 for &(m, x, y, r) in CASES.iter() {
634 assert_eq!(x.powm(y, &m), r);
635 assert_eq!((x as u16).powm(y as u16, &(m as _)), r as _);
636 assert_eq!((x as u32).powm(y as u32, &(m as _)), r as _);
637 assert_eq!((x as u64).powm(y as u64, &(m as _)), r as _);
638 assert_eq!((x as u128).powm(y as u128, &(m as _)), r as _);
639 }
640 }
641
642 #[test]
643 fn invm_test() {
644 const CASES: [(u64, u64, u64); 8] = [
646 (5, 11, 9),
648 (8, 11, 7),
649 (10, 11, 10),
650 (3, 5000, 1667),
651 (1667, 5000, 3),
652 (999, 5000, 3999),
653 (999, 9_223_372_036_854_775_807, 3_619_181_019_466_538_655),
654 (
655 9_223_372_036_854_775_804,
656 9_223_372_036_854_775_807,
657 3_074_457_345_618_258_602,
658 ),
659 ];
660
661 for &(a, m, x) in CASES.iter() {
662 assert_eq!(a.invm(&m).unwrap(), x);
663 }
664
665 for _ in 0..NRANDOM {
667 let a = random::<u32>() as u64;
668 let m = random::<u32>() as u64;
669 if let Some(ia) = a.invm(&m) {
670 assert_eq!(a.mulm(ia, &m), 1);
671 }
672
673 let a = random::<u64>() as u128;
674 let m = random::<u64>() as u128;
675 if let Some(ia) = a.invm(&m) {
676 assert_eq!(a.mulm(ia, &m), 1);
677 }
678 }
679 }
680
681 #[test]
682 fn dblm_and_sqm_test() {
683 for _ in 0..NRANDOM {
685 let a = random::<u64>();
686 let m = random::<u64>();
687 assert_eq!(a.addm(a, &m), a.dblm(&m));
688 assert_eq!(a.mulm(2, &m), a.dblm(&m));
689 assert_eq!(a.mulm(a, &m), a.sqm(&m));
690 assert_eq!(a.powm(2, &m), a.sqm(&m));
691
692 let a = random::<u128>();
693 let m = random::<u128>();
694 assert_eq!(a.addm(a, &m), a.dblm(&m));
695 assert_eq!(a.mulm(2, &m), a.dblm(&m));
696 assert_eq!(a.mulm(a, &m), a.sqm(&m));
697 assert_eq!(a.powm(2, &m), a.sqm(&m));
698 }
699 }
700
701 #[test]
702 fn legendre_test() {
703 const CASES: [(u8, u8, i8); 18] = [
704 (0, 11, 0),
705 (1, 11, 1),
706 (2, 11, -1),
707 (4, 11, 1),
708 (7, 11, -1),
709 (10, 11, -1),
710 (0, 17, 0),
711 (1, 17, 1),
712 (2, 17, 1),
713 (4, 17, 1),
714 (9, 17, 1),
715 (10, 17, -1),
716 (0, 101, 0),
717 (1, 101, 1),
718 (2, 101, -1),
719 (4, 101, 1),
720 (9, 101, 1),
721 (10, 101, -1),
722 ];
723
724 for &(a, n, res) in CASES.iter() {
725 assert_eq!(a.legendre(&n), res);
726 assert_eq!((a as u16).legendre(&(n as u16)), res);
727 assert_eq!((a as u32).legendre(&(n as u32)), res);
728 assert_eq!((a as u64).legendre(&(n as u64)), res);
729 assert_eq!((a as u128).legendre(&(n as u128)), res);
730 }
731
732 const SIGNED_CASES: [(i8, i8, i8); 15] = [
733 (-10, 11, 1),
734 (-7, 11, 1),
735 (-4, 11, -1),
736 (-2, 11, 1),
737 (-1, 11, -1),
738 (-10, 17, -1),
739 (-9, 17, 1),
740 (-4, 17, 1),
741 (-2, 17, 1),
742 (-1, 17, 1),
743 (-10, 101, -1),
744 (-9, 101, 1),
745 (-4, 101, 1),
746 (-2, 101, -1),
747 (-1, 101, 1),
748 ];
749
750 for &(a, n, res) in SIGNED_CASES.iter() {
751 assert_eq!(a.legendre(&n), res);
752 assert_eq!((a as i16).legendre(&(n as i16)), res);
753 assert_eq!((a as i32).legendre(&(n as i32)), res);
754 assert_eq!((a as i64).legendre(&(n as i64)), res);
755 assert_eq!((a as i128).legendre(&(n as i128)), res);
756 }
757 }
758
759 #[test]
760 fn jacobi_test() {
761 const CASES: [(u8, u8, i8); 15] = [
762 (1, 1, 1),
763 (15, 1, 1),
764 (2, 3, -1),
765 (29, 9, 1),
766 (4, 11, 1),
767 (17, 11, -1),
768 (19, 29, -1),
769 (10, 33, -1),
770 (11, 33, 0),
771 (12, 33, 0),
772 (14, 33, -1),
773 (15, 33, 0),
774 (15, 37, -1),
775 (29, 59, 1),
776 (30, 59, -1),
777 ];
778
779 for &(a, n, res) in CASES.iter() {
780 assert_eq!(a.jacobi(&n), res, "{}, {}", a, n);
781 assert_eq!((a as u16).jacobi(&(n as u16)), res);
782 assert_eq!((a as u32).jacobi(&(n as u32)), res);
783 assert_eq!((a as u64).jacobi(&(n as u64)), res);
784 assert_eq!((a as u128).jacobi(&(n as u128)), res);
785 }
786
787 const SIGNED_CASES: [(i8, i8, i8); 15] = [
788 (-10, 15, 0),
789 (-7, 15, 1),
790 (-4, 15, -1),
791 (-2, 15, -1),
792 (-1, 15, -1),
793 (-10, 13, 1),
794 (-9, 13, 1),
795 (-4, 13, 1),
796 (-2, 13, -1),
797 (-1, 13, 1),
798 (-10, 11, 1),
799 (-9, 11, -1),
800 (-4, 11, -1),
801 (-2, 11, 1),
802 (-1, 11, -1),
803 ];
804
805 for &(a, n, res) in SIGNED_CASES.iter() {
806 assert_eq!(a.jacobi(&n), res);
807 assert_eq!((a as i16).jacobi(&(n as i16)), res);
808 assert_eq!((a as i32).jacobi(&(n as i32)), res);
809 assert_eq!((a as i64).jacobi(&(n as i64)), res);
810 assert_eq!((a as i128).jacobi(&(n as i128)), res);
811 }
812 }
813
814 #[test]
815 fn kronecker_test() {
816 const CASES: [(u8, u8, i8); 18] = [
817 (0, 15, 0),
818 (1, 15, 1),
819 (2, 15, 1),
820 (4, 15, 1),
821 (7, 15, -1),
822 (10, 15, 0),
823 (0, 14, 0),
824 (1, 14, 1),
825 (2, 14, 0),
826 (4, 14, 0),
827 (9, 14, 1),
828 (10, 14, 0),
829 (0, 11, 0),
830 (1, 11, 1),
831 (2, 11, -1),
832 (4, 11, 1),
833 (9, 11, 1),
834 (10, 11, -1),
835 ];
836
837 for &(a, n, res) in CASES.iter() {
838 assert_eq!(a.kronecker(&n), res);
839 assert_eq!((a as u16).kronecker(&(n as u16)), res);
840 assert_eq!((a as u32).kronecker(&(n as u32)), res);
841 assert_eq!((a as u64).kronecker(&(n as u64)), res);
842 assert_eq!((a as u128).kronecker(&(n as u128)), res);
843 }
844
845 const SIGNED_CASES: [(i8, i8, i8); 37] = [
846 (-10, 15, 0),
847 (-7, 15, 1),
848 (-4, 15, -1),
849 (-2, 15, -1),
850 (-1, 15, -1),
851 (-10, 14, 0),
852 (-9, 14, -1),
853 (-4, 14, 0),
854 (-2, 14, 0),
855 (-1, 14, -1),
856 (-10, 11, 1),
857 (-9, 11, -1),
858 (-4, 11, -1),
859 (-2, 11, 1),
860 (-1, 11, -1),
861 (-10, -11, -1),
862 (-9, -11, 1),
863 (-4, -11, 1),
864 (-2, -11, -1),
865 (-1, -11, 1),
866 (0, -11, 0),
867 (1, -11, 1),
868 (2, -11, -1),
869 (4, -11, 1),
870 (9, -11, 1),
871 (10, -11, -1),
872 (-10, 32, 0),
873 (-9, 32, 1),
874 (-4, 32, 0),
875 (-2, 32, 0),
876 (-1, 32, 1),
877 (0, 32, 0),
878 (1, 32, 1),
879 (2, 32, 0),
880 (4, 32, 0),
881 (9, 32, 1),
882 (10, 32, 0),
883 ];
884
885 for &(a, n, res) in SIGNED_CASES.iter() {
886 assert_eq!(a.kronecker(&n), res, "{}, {}", a, n);
887 assert_eq!((a as i16).kronecker(&(n as i16)), res);
888 assert_eq!((a as i32).kronecker(&(n as i32)), res);
889 assert_eq!((a as i64).kronecker(&(n as i64)), res);
890 assert_eq!((a as i128).kronecker(&(n as i128)), res);
891 }
892 }
893}