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