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);
283macro_rules! impl_const_powm {
284 ($name:ident, $T:ty, $D:ty) => {
285 pub const fn $name(base: $T, exp: $T, m: $T) -> $T {
287 if m <= 1 {
288 return 0;
289 }
290 let mut base = base % m;
291 let mut result: $T = 1;
292 let mut exp = exp;
293 while exp > 0 {
294 if exp & 1 == 1 {
295 result = (((result as $D) * (base as $D)) % (m as $D)) as $T;
296 }
297 exp >>= 1;
298 base = (((base as $D) * (base as $D)) % (m as $D)) as $T;
299 }
300 result
301 }
302 };
303}
304impl_const_powm!(powm_u32, u32, u64);
305impl_const_powm!(powm_u64, u64, u128);
306
307macro_rules! impl_mod_ops_by_deref {
309 ($($T:ty)*) => {$(
310 impl ModularCoreOps<$T, &$T> for &$T {
312 type Output = $T;
313 #[inline]
314 fn addm(self, rhs: $T, m: &$T) -> $T {
315 (*self).addm(rhs, &m)
316 }
317 #[inline]
318 fn subm(self, rhs: $T, m: &$T) -> $T {
319 (*self).subm(rhs, &m)
320 }
321 #[inline]
322 fn mulm(self, rhs: $T, m: &$T) -> $T {
323 (*self).mulm(rhs, &m)
324 }
325 }
326 impl ModularCoreOps<&$T, &$T> for $T {
327 type Output = $T;
328 #[inline]
329 fn addm(self, rhs: &$T, m: &$T) -> $T {
330 self.addm(*rhs, &m)
331 }
332 #[inline]
333 fn subm(self, rhs: &$T, m: &$T) -> $T {
334 self.subm(*rhs, &m)
335 }
336 #[inline]
337 fn mulm(self, rhs: &$T, m: &$T) -> $T {
338 self.mulm(*rhs, &m)
339 }
340 }
341 impl ModularCoreOps<&$T, &$T> for &$T {
342 type Output = $T;
343 #[inline]
344 fn addm(self, rhs: &$T, m: &$T) -> $T {
345 (*self).addm(*rhs, &m)
346 }
347 #[inline]
348 fn subm(self, rhs: &$T, m: &$T) -> $T {
349 (*self).subm(*rhs, &m)
350 }
351 #[inline]
352 fn mulm(self, rhs: &$T, m: &$T) -> $T {
353 (*self).mulm(*rhs, &m)
354 }
355 }
356
357 impl ModularPow<$T, &$T> for &$T {
359 type Output = $T;
360 #[inline]
361 fn powm(self, exp: $T, m: &$T) -> $T {
362 (*self).powm(exp, &m)
363 }
364 }
365 impl ModularPow<&$T, &$T> for $T {
366 type Output = $T;
367 #[inline]
368 fn powm(self, exp: &$T, m: &$T) -> $T {
369 self.powm(*exp, &m)
370 }
371 }
372 impl ModularPow<&$T, &$T> for &$T {
373 type Output = $T;
374 #[inline]
375 fn powm(self, exp: &$T, m: &$T) -> $T {
376 (*self).powm(*exp, &m)
377 }
378 }
379
380 impl ModularUnaryOps<&$T> for &$T {
382 type Output = $T;
383
384 #[inline]
385 fn negm(self, m: &$T) -> $T {
386 ModularUnaryOps::<&$T>::negm(*self, m)
387 }
388 #[inline]
389 fn invm(self, m: &$T) -> Option<$T> {
390 ModularUnaryOps::<&$T>::invm(*self, m)
391 }
392 #[inline]
393 fn dblm(self, m: &$T) -> $T {
394 ModularUnaryOps::<&$T>::dblm(*self, m)
395 }
396 #[inline]
397 fn sqm(self, m: &$T) -> $T {
398 ModularUnaryOps::<&$T>::sqm(*self, m)
399 }
400 }
401 )*};
402}
403
404impl_mod_ops_by_deref!(u8 u16 u32 u64 u128 usize);
405
406macro_rules! impl_absm_for_prim {
407 ($($signed:ty => $unsigned:ty;)*) => {$(
408 impl ModularAbs<$unsigned> for $signed {
409 fn absm(self, m: &$unsigned) -> $unsigned {
410 if self >= 0 {
411 (self as $unsigned) % m
412 } else {
413 (-self as $unsigned).negm(m)
414 }
415 }
416 }
417 )*};
418}
419
420impl_absm_for_prim! {
421 i8 => u8; i16 => u16; i32 => u32; i64 => u64; i128 => u128; isize => usize;
422}
423
424macro_rules! impl_div_exact_for_prim {
425 ($($t:ty)*) => {$(
426 impl DivExact<$t, ()> for $t {
427 type Output = $t;
428 #[inline]
429 fn div_exact(self, d: $t, _: &()) -> Option<Self::Output> {
430 let (q, r) = (self / d, self % d);
431 if r == 0 {
432 Some(q)
433 } else {
434 None
435 }
436 }
437 }
438 )*};
439}
440
441impl_div_exact_for_prim!(u8 u16 u32 u64 u128);
442
443#[cfg(test)]
444mod tests {
445 use super::*;
446 use core::ops::Neg;
447 use rand::random;
448
449 const NRANDOM: u32 = 10; #[test]
452 fn addm_test() {
453 const CASES: [(u8, u8, u8, u8); 10] = [
455 (5, 0, 0, 0),
457 (5, 1, 2, 3),
458 (5, 2, 1, 3),
459 (5, 2, 2, 4),
460 (5, 3, 2, 0),
461 (5, 2, 3, 0),
462 (5, 6, 1, 2),
463 (5, 1, 6, 2),
464 (5, 11, 7, 3),
465 (5, 7, 11, 3),
466 ];
467
468 for &(m, x, y, r) in CASES.iter() {
469 assert_eq!(x.addm(y, &m), r);
470 assert_eq!((x as u16).addm(y as u16, &(m as _)), r as _);
471 assert_eq!((x as u32).addm(y as u32, &(m as _)), r as _);
472 assert_eq!((x as u64).addm(y as u64, &(m as _)), r as _);
473 assert_eq!((x as u128).addm(y as u128, &(m as _)), r as _);
474 }
475
476 for _ in 0..NRANDOM {
478 let a = random::<u32>() as u64;
479 let b = random::<u32>() as u64;
480 let m = random::<u32>() as u64;
481 assert_eq!(a.addm(b, &m), (a + b) % m);
482 assert_eq!(
483 a.addm(b, &(1u64 << 32)) as u32,
484 (a as u32).wrapping_add(b as u32)
485 );
486
487 let a = random::<u64>() as u128;
488 let b = random::<u64>() as u128;
489 let m = random::<u64>() as u128;
490 assert_eq!(a.addm(b, &m), (a + b) % m);
491 assert_eq!(
492 a.addm(b, &(1u128 << 64)) as u64,
493 (a as u64).wrapping_add(b as u64)
494 );
495 }
496 }
497
498 #[test]
499 fn subm_test() {
500 const CASES: [(u8, u8, u8, u8); 10] = [
502 (7, 0, 0, 0),
504 (7, 11, 9, 2),
505 (7, 5, 2, 3),
506 (7, 2, 5, 4),
507 (7, 6, 7, 6),
508 (7, 1, 7, 1),
509 (7, 7, 1, 6),
510 (7, 0, 6, 1),
511 (7, 15, 1, 0),
512 (7, 1, 15, 0),
513 ];
514
515 for &(m, x, y, r) in CASES.iter() {
516 assert_eq!(x.subm(y, &m), r);
517 assert_eq!((x as u16).subm(y as u16, &(m as _)), r as _);
518 assert_eq!((x as u32).subm(y as u32, &(m as _)), r as _);
519 assert_eq!((x as u64).subm(y as u64, &(m as _)), r as _);
520 assert_eq!((x as u128).subm(y as u128, &(m as _)), r as _);
521 }
522
523 for _ in 0..NRANDOM {
525 let a = random::<u32>() as u64;
526 let b = random::<u32>() as u64;
527 let m = random::<u32>() as u64;
528 assert_eq!(
529 a.subm(b, &m),
530 (a as i64 - b as i64).rem_euclid(m as i64) as u64
531 );
532 assert_eq!(
533 a.subm(b, &(1u64 << 32)) as u32,
534 (a as u32).wrapping_sub(b as u32)
535 );
536
537 let a = random::<u64>() as u128;
538 let b = random::<u64>() as u128;
539 let m = random::<u64>() as u128;
540 assert_eq!(
541 a.subm(b, &m),
542 (a as i128 - b as i128).rem_euclid(m as i128) as u128
543 );
544 assert_eq!(
545 a.subm(b, &(1u128 << 64)) as u64,
546 (a as u64).wrapping_sub(b as u64)
547 );
548 }
549 }
550
551 #[test]
552 fn negm_and_absm_test() {
553 const CASES: [(u8, u8, u8); 5] = [
555 (5, 0, 0),
557 (5, 2, 3),
558 (5, 1, 4),
559 (5, 5, 0),
560 (5, 12, 3),
561 ];
562
563 for &(m, x, r) in CASES.iter() {
564 assert_eq!(x.negm(&m), r);
565 assert_eq!((x as i8).neg().absm(&m), r);
566 assert_eq!((x as u16).negm(&(m as _)), r as _);
567 assert_eq!((x as i16).neg().absm(&(m as u16)), r as _);
568 assert_eq!((x as u32).negm(&(m as _)), r as _);
569 assert_eq!((x as i32).neg().absm(&(m as u32)), r as _);
570 assert_eq!((x as u64).negm(&(m as _)), r as _);
571 assert_eq!((x as i64).neg().absm(&(m as u64)), r as _);
572 assert_eq!((x as u128).negm(&(m as _)), r as _);
573 assert_eq!((x as i128).neg().absm(&(m as u128)), r as _);
574 }
575
576 for _ in 0..NRANDOM {
578 let a = random::<u32>() as u64;
579 let m = random::<u32>() as u64;
580 assert_eq!(a.negm(&m), (a as i64).neg().rem_euclid(m as i64) as u64);
581 assert_eq!(a.negm(&(1u64 << 32)) as u32, (a as u32).wrapping_neg());
582
583 let a = random::<u64>() as u128;
584 let m = random::<u64>() as u128;
585 assert_eq!(a.negm(&m), (a as i128).neg().rem_euclid(m as i128) as u128);
586 assert_eq!(a.negm(&(1u128 << 64)) as u64, (a as u64).wrapping_neg());
587 }
588 }
589
590 #[test]
591 fn mulm_test() {
592 const CASES: [(u8, u8, u8, u8); 10] = [
594 (7, 0, 0, 0),
596 (7, 11, 9, 1),
597 (7, 5, 2, 3),
598 (7, 2, 5, 3),
599 (7, 6, 7, 0),
600 (7, 1, 7, 0),
601 (7, 7, 1, 0),
602 (7, 0, 6, 0),
603 (7, 15, 1, 1),
604 (7, 1, 15, 1),
605 ];
606
607 for &(m, x, y, r) in CASES.iter() {
608 assert_eq!(x.mulm(y, &m), r);
609 assert_eq!((x as u16).mulm(y as u16, &(m as _)), r as _);
610 assert_eq!((x as u32).mulm(y as u32, &(m as _)), r as _);
611 assert_eq!((x as u64).mulm(y as u64, &(m as _)), r as _);
612 assert_eq!((x as u128).mulm(y as u128, &(m as _)), r as _);
613 }
614
615 for _ in 0..NRANDOM {
617 let a = random::<u32>() as u64;
618 let b = random::<u32>() as u64;
619 let m = random::<u32>() as u64;
620 assert_eq!(a.mulm(b, &m), (a * b) % m);
621 assert_eq!(
622 a.mulm(b, &(1u64 << 32)) as u32,
623 (a as u32).wrapping_mul(b as u32)
624 );
625
626 let a = random::<u64>() as u128;
627 let b = random::<u64>() as u128;
628 let m = random::<u64>() as u128;
629 assert_eq!(a.mulm(b, &m), (a * b) % m);
630 assert_eq!(
631 a.mulm(b, &(1u128 << 32)) as u32,
632 (a as u32).wrapping_mul(b as u32)
633 );
634 }
635 }
636
637 #[test]
638 fn powm_test() {
639 const CASES: [(u8, u8, u8, u8); 12] = [
641 (7, 0, 0, 1),
643 (7, 11, 9, 1),
644 (7, 5, 2, 4),
645 (7, 2, 5, 4),
646 (7, 6, 7, 6),
647 (7, 1, 7, 1),
648 (7, 7, 1, 0),
649 (7, 0, 6, 0),
650 (7, 15, 1, 1),
651 (7, 1, 15, 1),
652 (7, 255, 255, 6),
653 (10, 255, 255, 5),
654 ];
655
656 for &(m, x, y, r) in CASES.iter() {
657 assert_eq!(x.powm(y, &m), r);
658 assert_eq!((x as u16).powm(y as u16, &(m as _)), r as _);
659 assert_eq!((x as u32).powm(y as u32, &(m as _)), r as _);
660 assert_eq!((x as u64).powm(y as u64, &(m as _)), r as _);
661 assert_eq!((x as u128).powm(y as u128, &(m as _)), r as _);
662 }
663 }
664
665 #[test]
666 fn invm_test() {
667 const CASES: [(u64, u64, u64); 8] = [
669 (5, 11, 9),
671 (8, 11, 7),
672 (10, 11, 10),
673 (3, 5000, 1667),
674 (1667, 5000, 3),
675 (999, 5000, 3999),
676 (999, 9_223_372_036_854_775_807, 3_619_181_019_466_538_655),
677 (
678 9_223_372_036_854_775_804,
679 9_223_372_036_854_775_807,
680 3_074_457_345_618_258_602,
681 ),
682 ];
683
684 for &(a, m, x) in CASES.iter() {
685 assert_eq!(a.invm(&m).unwrap(), x);
686 }
687
688 for _ in 0..NRANDOM {
690 let a = random::<u32>() as u64;
691 let m = random::<u32>() as u64;
692 if let Some(ia) = a.invm(&m) {
693 assert_eq!(a.mulm(ia, &m), 1);
694 }
695
696 let a = random::<u64>() as u128;
697 let m = random::<u64>() as u128;
698 if let Some(ia) = a.invm(&m) {
699 assert_eq!(a.mulm(ia, &m), 1);
700 }
701 }
702 }
703
704 #[test]
705 fn const_powm_test() {
706 for _ in 0..NRANDOM {
708 let a = random::<u32>();
709 let m = random::<u32>().max(2);
710 let exp = random::<u32>() % 32;
711 assert_eq!(powm_u32(a, exp, m), a.powm(exp, &m));
712
713 let a = random::<u64>();
714 let m = random::<u64>().max(2);
715 let exp = random::<u64>() % 32;
716 assert_eq!(powm_u64(a, exp, m), a.powm(exp, &m));
717 }
718 }
719
720 #[test]
721 fn dblm_and_sqm_test() {
722 for _ in 0..NRANDOM {
724 let a = random::<u64>();
725 let m = random::<u64>();
726 assert_eq!(a.addm(a, &m), a.dblm(&m));
727 assert_eq!(a.mulm(2, &m), a.dblm(&m));
728 assert_eq!(a.mulm(a, &m), a.sqm(&m));
729 assert_eq!(a.powm(2, &m), a.sqm(&m));
730
731 let a = random::<u128>();
732 let m = random::<u128>();
733 assert_eq!(a.addm(a, &m), a.dblm(&m));
734 assert_eq!(a.mulm(2, &m), a.dblm(&m));
735 assert_eq!(a.mulm(a, &m), a.sqm(&m));
736 assert_eq!(a.powm(2, &m), a.sqm(&m));
737 }
738 }
739
740 #[test]
741 fn legendre_test() {
742 const CASES: [(u8, u8, i8); 18] = [
743 (0, 11, 0),
744 (1, 11, 1),
745 (2, 11, -1),
746 (4, 11, 1),
747 (7, 11, -1),
748 (10, 11, -1),
749 (0, 17, 0),
750 (1, 17, 1),
751 (2, 17, 1),
752 (4, 17, 1),
753 (9, 17, 1),
754 (10, 17, -1),
755 (0, 101, 0),
756 (1, 101, 1),
757 (2, 101, -1),
758 (4, 101, 1),
759 (9, 101, 1),
760 (10, 101, -1),
761 ];
762
763 for &(a, n, res) in CASES.iter() {
764 assert_eq!(a.legendre(&n), res);
765 assert_eq!((a as u16).legendre(&(n as u16)), res);
766 assert_eq!((a as u32).legendre(&(n as u32)), res);
767 assert_eq!((a as u64).legendre(&(n as u64)), res);
768 assert_eq!((a as u128).legendre(&(n as u128)), res);
769 }
770
771 const SIGNED_CASES: [(i8, i8, i8); 15] = [
772 (-10, 11, 1),
773 (-7, 11, 1),
774 (-4, 11, -1),
775 (-2, 11, 1),
776 (-1, 11, -1),
777 (-10, 17, -1),
778 (-9, 17, 1),
779 (-4, 17, 1),
780 (-2, 17, 1),
781 (-1, 17, 1),
782 (-10, 101, -1),
783 (-9, 101, 1),
784 (-4, 101, 1),
785 (-2, 101, -1),
786 (-1, 101, 1),
787 ];
788
789 for &(a, n, res) in SIGNED_CASES.iter() {
790 assert_eq!(a.legendre(&n), res);
791 assert_eq!((a as i16).legendre(&(n as i16)), res);
792 assert_eq!((a as i32).legendre(&(n as i32)), res);
793 assert_eq!((a as i64).legendre(&(n as i64)), res);
794 assert_eq!((a as i128).legendre(&(n as i128)), res);
795 }
796 }
797
798 #[test]
799 fn jacobi_test() {
800 const CASES: [(u8, u8, i8); 15] = [
801 (1, 1, 1),
802 (15, 1, 1),
803 (2, 3, -1),
804 (29, 9, 1),
805 (4, 11, 1),
806 (17, 11, -1),
807 (19, 29, -1),
808 (10, 33, -1),
809 (11, 33, 0),
810 (12, 33, 0),
811 (14, 33, -1),
812 (15, 33, 0),
813 (15, 37, -1),
814 (29, 59, 1),
815 (30, 59, -1),
816 ];
817
818 for &(a, n, res) in CASES.iter() {
819 assert_eq!(a.jacobi(&n), res, "{}, {}", a, n);
820 assert_eq!((a as u16).jacobi(&(n as u16)), res);
821 assert_eq!((a as u32).jacobi(&(n as u32)), res);
822 assert_eq!((a as u64).jacobi(&(n as u64)), res);
823 assert_eq!((a as u128).jacobi(&(n as u128)), res);
824 }
825
826 const SIGNED_CASES: [(i8, i8, i8); 15] = [
827 (-10, 15, 0),
828 (-7, 15, 1),
829 (-4, 15, -1),
830 (-2, 15, -1),
831 (-1, 15, -1),
832 (-10, 13, 1),
833 (-9, 13, 1),
834 (-4, 13, 1),
835 (-2, 13, -1),
836 (-1, 13, 1),
837 (-10, 11, 1),
838 (-9, 11, -1),
839 (-4, 11, -1),
840 (-2, 11, 1),
841 (-1, 11, -1),
842 ];
843
844 for &(a, n, res) in SIGNED_CASES.iter() {
845 assert_eq!(a.jacobi(&n), res);
846 assert_eq!((a as i16).jacobi(&(n as i16)), res);
847 assert_eq!((a as i32).jacobi(&(n as i32)), res);
848 assert_eq!((a as i64).jacobi(&(n as i64)), res);
849 assert_eq!((a as i128).jacobi(&(n as i128)), res);
850 }
851 }
852
853 #[test]
854 fn kronecker_test() {
855 const CASES: [(u8, u8, i8); 18] = [
856 (0, 15, 0),
857 (1, 15, 1),
858 (2, 15, 1),
859 (4, 15, 1),
860 (7, 15, -1),
861 (10, 15, 0),
862 (0, 14, 0),
863 (1, 14, 1),
864 (2, 14, 0),
865 (4, 14, 0),
866 (9, 14, 1),
867 (10, 14, 0),
868 (0, 11, 0),
869 (1, 11, 1),
870 (2, 11, -1),
871 (4, 11, 1),
872 (9, 11, 1),
873 (10, 11, -1),
874 ];
875
876 for &(a, n, res) in CASES.iter() {
877 assert_eq!(a.kronecker(&n), res);
878 assert_eq!((a as u16).kronecker(&(n as u16)), res);
879 assert_eq!((a as u32).kronecker(&(n as u32)), res);
880 assert_eq!((a as u64).kronecker(&(n as u64)), res);
881 assert_eq!((a as u128).kronecker(&(n as u128)), res);
882 }
883
884 const SIGNED_CASES: [(i8, i8, i8); 37] = [
885 (-10, 15, 0),
886 (-7, 15, 1),
887 (-4, 15, -1),
888 (-2, 15, -1),
889 (-1, 15, -1),
890 (-10, 14, 0),
891 (-9, 14, -1),
892 (-4, 14, 0),
893 (-2, 14, 0),
894 (-1, 14, -1),
895 (-10, 11, 1),
896 (-9, 11, -1),
897 (-4, 11, -1),
898 (-2, 11, 1),
899 (-1, 11, -1),
900 (-10, -11, -1),
901 (-9, -11, 1),
902 (-4, -11, 1),
903 (-2, -11, -1),
904 (-1, -11, 1),
905 (0, -11, 0),
906 (1, -11, 1),
907 (2, -11, -1),
908 (4, -11, 1),
909 (9, -11, 1),
910 (10, -11, -1),
911 (-10, 32, 0),
912 (-9, 32, 1),
913 (-4, 32, 0),
914 (-2, 32, 0),
915 (-1, 32, 1),
916 (0, 32, 0),
917 (1, 32, 1),
918 (2, 32, 0),
919 (4, 32, 0),
920 (9, 32, 1),
921 (10, 32, 0),
922 ];
923
924 for &(a, n, res) in SIGNED_CASES.iter() {
925 assert_eq!(a.kronecker(&n), res, "{}, {}", a, n);
926 assert_eq!((a as i16).kronecker(&(n as i16)), res);
927 assert_eq!((a as i32).kronecker(&(n as i32)), res);
928 assert_eq!((a as i64).kronecker(&(n as i64)), res);
929 assert_eq!((a as i128).kronecker(&(n as i128)), res);
930 }
931 }
932}