num_bigint_dig/algorithms/
jacobi.rs1use crate::integer::Integer;
2use num_traits::{One, Signed, Zero};
3
4use crate::BigInt;
5
6pub fn jacobi(x: &BigInt, y: &BigInt) -> isize {
9 if !y.is_odd() {
10 panic!(
11 "invalid arguments, y must be an odd integer,but got {:?}",
12 y
13 );
14 }
15
16 let mut a = x.clone();
17 let mut b = y.clone();
18 let mut j = 1;
19
20 if b.is_negative() {
21 if a.is_negative() {
22 j = -1;
23 }
24 b = -b;
25 }
26
27 loop {
28 if b.is_one() {
29 return j;
30 }
31 if a.is_zero() {
32 return 0;
33 }
34
35 a = a.mod_floor(&b);
36 if a.is_zero() {
37 return 0;
38 }
39
40 let s = a.trailing_zeros().unwrap();
44 if s & 1 != 0 {
45 let bmod8 = b.get_limb(0) & 7;
46 if bmod8 == 3 || bmod8 == 5 {
47 j = -j;
48 }
49 }
50
51 let c = &a >> s; if b.get_limb(0) & 3 == 3 && c.get_limb(0) & 3 == 3 {
55 j = -j
56 }
57
58 a = b;
59 b = c;
60 }
61}
62
63#[cfg(test)]
64mod tests {
65 use super::*;
66
67 use num_traits::FromPrimitive;
68
69 use crate::BigInt;
70
71 #[test]
72 fn test_jacobi() {
73 let cases = [
74 [0, 1, 1],
75 [0, -1, 1],
76 [1, 1, 1],
77 [1, -1, 1],
78 [0, 5, 0],
79 [1, 5, 1],
80 [2, 5, -1],
81 [-2, 5, -1],
82 [2, -5, -1],
83 [-2, -5, 1],
84 [3, 5, -1],
85 [5, 5, 0],
86 [-5, 5, 0],
87 [6, 5, 1],
88 [6, -5, 1],
89 [-6, 5, 1],
90 [-6, -5, -1],
91 ];
92
93 for case in cases.iter() {
94 let x = BigInt::from_i64(case[0]).unwrap();
95 let y = BigInt::from_i64(case[1]).unwrap();
96
97 assert_eq!(case[2] as isize, jacobi(&x, &y), "jacobi({}, {})", x, y);
98 }
99 }
100}