malachite_base/num/arithmetic/kronecker_symbol.rs
1// Copyright © 2025 Mikhail Hogrefe
2//
3// Uses code adopted from the GNU MP Library.
4//
5// Copyright © 1996, 1998, 2000-2004, 2008, 2010 Free Software Foundation, Inc.
6//
7// Uses code adopted from the FLINT Library.
8//
9// Copyright © 2008 Peter Shrimpton
10//
11// Copyright © 2009 William Hart
12//
13// This file is part of Malachite.
14//
15// Malachite is free software: you can redistribute it and/or modify it under the terms of the GNU
16// Lesser General Public License (LGPL) as published by the Free Software Foundation; either version
17// 3 of the License, or (at your option) any later version. See <https://www.gnu.org/licenses/>.
18
19use crate::fail_on_untested_path;
20use crate::num::arithmetic::traits::{
21 JacobiSymbol, KroneckerSymbol, LegendreSymbol, ModPowerOf2, NegAssign, Parity, UnsignedAbs,
22};
23use crate::num::basic::signeds::PrimitiveSigned;
24use crate::num::basic::unsigneds::PrimitiveUnsigned;
25use crate::num::conversion::traits::SplitInHalf;
26use crate::num::logic::traits::NotAssign;
27use core::mem::swap;
28
29pub_test! {jacobi_symbol_unsigned_simple<T: PrimitiveUnsigned>(mut a: T, mut n: T) -> i8 {
30 assert_ne!(n, T::ZERO);
31 assert!(n.odd());
32 a %= n;
33 let mut t = 1i8;
34 while a != T::ZERO {
35 while a.even() {
36 a >>= 1;
37 let r: u8 = n.mod_power_of_2(3).wrapping_into();
38 if r == 3 || r == 5 {
39 t.neg_assign();
40 }
41 }
42 swap(&mut a, &mut n);
43 if (a & n).get_bit(1) {
44 t.neg_assign();
45 }
46 a %= n;
47 }
48 if n == T::ONE {
49 t
50 } else {
51 0
52 }
53}}
54
55// Computes (a / b) where b is odd, and a and b are otherwise arbitrary two-limb numbers.
56//
57// This is equivalent to `mpn_jacobi_2` from `mpn/jacobi_2.c`, GMP 6.2.1, where `JACOBI_2_METHOD ==
58// 2` and `bit` is 0.
59pub_test! {jacobi_symbol_unsigned_double_fast_2<T: PrimitiveUnsigned>(
60 mut x_1: T,
61 mut x_0: T,
62 mut y_1: T,
63 mut y_0: T,
64) -> i8 {
65 assert!(y_0.odd());
66 if y_1 == T::ZERO && y_0 == T::ONE {
67 // (x|1) = 1
68 return 1;
69 }
70 let mut bit = false;
71 if x_0 == T::ZERO {
72 if x_1 == T::ZERO {
73 // (0|y) = 0, y > 1
74 return 0;
75 }
76 let c = x_1.trailing_zeros();
77 if c.odd() && (y_0 ^ (y_0 >> 1)).get_bit(1) {
78 bit.not_assign();
79 }
80 x_0 = y_0;
81 y_0 = x_1 >> c;
82 if y_0 == T::ONE {
83 // (1|y) = 1
84 return if bit { -1 } else { 1 };
85 }
86 x_1 = y_1;
87 if (x_0 & y_0).get_bit(1) {
88 bit.not_assign();
89 }
90 } else {
91 if x_0.even() {
92 let c = x_0.trailing_zeros();
93 x_0 = (x_1 << (T::WIDTH - c)) | (x_0 >> c);
94 x_1 >>= c;
95 if c.odd() && (y_0 ^ (y_0 >> 1)).get_bit(1) {
96 bit.not_assign();
97 }
98 }
99 let mut skip_loop = false;
100 if x_1 == T::ZERO {
101 if y_1 == T::ZERO {
102 assert!(y_0.odd());
103 assert!(y_0 > T::ONE);
104 let j = x_0.jacobi_symbol(y_0);
105 return if bit { -j } else { j };
106 }
107 if (x_0 & y_0).get_bit(1) {
108 bit.not_assign();
109 }
110 swap(&mut x_0, &mut y_0);
111 x_1 = y_1;
112 skip_loop = true;
113 }
114 if !skip_loop {
115 'outer: while y_1 != T::ZERO {
116 // Compute (x|y)
117 while x_1 > y_1 {
118 (x_1, x_0) = T::xx_sub_yy_to_zz(x_1, x_0, y_1, y_0);
119 if x_0 == T::ZERO {
120 let c = x_1.trailing_zeros();
121 if c.odd() && (y_0 ^ (y_0 >> 1)).get_bit(1) {
122 bit.not_assign();
123 }
124 x_0 = y_0;
125 y_0 = x_1 >> c;
126 x_1 = y_1;
127 if (x_0 & y_0).get_bit(1) {
128 bit.not_assign();
129 }
130 break 'outer;
131 }
132 let c = x_0.trailing_zeros();
133 if c.odd() && (y_0 ^ (y_0 >> 1)).get_bit(1) {
134 bit.not_assign();
135 }
136 x_0 = (x_1 << (T::WIDTH - c)) | (x_0 >> c);
137 x_1 >>= c;
138 }
139 if x_1 != y_1 {
140 if x_1 == T::ZERO {
141 if (x_0 & y_0).get_bit(1) {
142 bit.not_assign();
143 }
144 swap(&mut x_0, &mut y_0);
145 x_1 = y_1;
146 break;
147 }
148 if (x_0 & y_0).get_bit(1) {
149 bit.not_assign();
150 }
151 // Compute (y|x)
152 while y_1 > x_1 {
153 (y_1, y_0) = T::xx_sub_yy_to_zz(y_1, y_0, x_1, x_0);
154 if y_0 == T::ZERO {
155 let c = y_1.trailing_zeros();
156 if c.odd() & (x_0 ^ (x_0 >> 1)).get_bit(1) {
157 bit.not_assign();
158 }
159 y_0 = y_1 >> c;
160 if (x_0 & y_0).get_bit(1) {
161 bit.not_assign();
162 }
163 break 'outer;
164 }
165 let c = y_0.trailing_zeros();
166 if c.odd() & (x_0 ^ (x_0 >> 1)).get_bit(1) {
167 bit.not_assign();
168 }
169 y_0 = (y_1 << (T::WIDTH - c)) | (y_0 >> c);
170 y_1 >>= c;
171 }
172 if (x_0 & y_0).get_bit(1) {
173 bit.not_assign();
174 }
175 }
176 // Compute (x|y)
177 if x_1 == y_1 {
178 if x_0 < y_0 {
179 swap(&mut x_0, &mut y_0);
180 if (x_0 & y_0).get_bit(1) {
181 bit.not_assign();
182 }
183 }
184 x_0 -= y_0;
185 if x_0 == T::ZERO {
186 return 0;
187 }
188 let c = x_0.trailing_zeros();
189 if c.odd() & (y_0 ^ (y_0 >> 1)).get_bit(1) {
190 bit.not_assign();
191 }
192 x_0 >>= c;
193 if x_0 == T::ONE {
194 return if bit { -1 } else { 1 };
195 }
196 swap(&mut x_0, &mut y_0);
197 if (x_0 & y_0).get_bit(1) {
198 bit.not_assign();
199 }
200 break;
201 }
202 }
203 }
204 }
205 // Compute (x|y), with y a single limb.
206 assert!(y_0.odd());
207 if y_0 == T::ONE {
208 // (x|1) = 1
209 return if bit { -1 } else { 1 };
210 }
211 while x_1 != T::ZERO {
212 x_1 -= if x_0 < y_0 { T::ONE } else { T::ZERO };
213 x_0.wrapping_sub_assign(y_0);
214 if x_0 == T::ZERO {
215 if x_1 == T::ZERO {
216 fail_on_untested_path(
217 "jacobi_symbol_unsigned_double_fast_2, x_1 == T::ZERO fourth time",
218 );
219 return 0;
220 }
221 let c = x_1.trailing_zeros();
222 if c.odd() && (y_0 ^ (y_0 >> 1)).get_bit(1) {
223 bit.not_assign();
224 }
225 x_0 = x_1 >> c;
226 break;
227 }
228 let c = x_0.trailing_zeros();
229 x_0 = (x_1 << (T::WIDTH - c)) | (x_0 >> c);
230 x_1 >>= c;
231 if c.odd() && (y_0 ^ (y_0 >> 1)).get_bit(1) {
232 bit.not_assign();
233 }
234 }
235 assert!(y_0.odd());
236 assert!(y_0 > T::ONE);
237 let j = x_0.jacobi_symbol(y_0);
238 if bit {
239 -j
240 } else {
241 j
242 }
243}}
244
245fn jacobi_symbol_signed<
246 U: PrimitiveUnsigned,
247 S: ModPowerOf2<Output = U> + PrimitiveSigned + UnsignedAbs<Output = U>,
248>(
249 a: S,
250 n: S,
251) -> i8 {
252 assert!(n > S::ZERO);
253 assert!(n.odd());
254 let s = a.unsigned_abs().jacobi_symbol(n.unsigned_abs());
255 if a < S::ZERO && n.get_bit(1) { -s } else { s }
256}
257
258fn kronecker_symbol_unsigned<T: PrimitiveUnsigned>(a: T, b: T) -> i8 {
259 if b == T::ZERO {
260 i8::from(a == T::ONE)
261 } else if a.even() && b.even() {
262 0
263 } else {
264 let b_twos = b.trailing_zeros();
265 let mut s = a.jacobi_symbol(b >> b_twos);
266 if b_twos.odd() {
267 let m: u32 = a.mod_power_of_2(3).wrapping_into();
268 if m == 3 || m == 5 {
269 s.neg_assign();
270 }
271 }
272 s
273 }
274}
275
276fn kronecker_symbol_signed<U: PrimitiveUnsigned, S: ModPowerOf2<Output = U> + PrimitiveSigned>(
277 a: S,
278 b: S,
279) -> i8 {
280 if b == S::ZERO {
281 i8::from(a == S::ONE || a == S::NEGATIVE_ONE)
282 } else if a.even() && b.even() {
283 0
284 } else {
285 let b_twos = b.trailing_zeros();
286 let mut s = a.jacobi_symbol((b >> b_twos).abs());
287 if a < S::ZERO && b < S::ZERO {
288 s.neg_assign();
289 }
290 if b_twos.odd() {
291 let m: u32 = a.mod_power_of_2(3).wrapping_into();
292 if m == 3 || m == 5 {
293 s.neg_assign();
294 }
295 }
296 s
297 }
298}
299
300macro_rules! impl_symbols {
301 ($u:ident, $s:ident) => {
302 impl LegendreSymbol<$u> for $u {
303 /// Computes the Legendre symbol of two numbers.
304 ///
305 /// This implementation is identical to that of [`JacobiSymbol`], since there is no
306 /// computational benefit to requiring that the denominator be prime.
307 ///
308 /// $$
309 /// f(x, y) = \left ( \frac{x}{y} \right ).
310 /// $$
311 ///
312 /// # Worst-case complexity
313 /// $T(n) = O(n^2)$
314 ///
315 /// $M(n) = O(n)$
316 ///
317 /// where $T$ is time, $M$ is additional memory, and $n$ is
318 /// `max(self.significant_bits(), other.significant_bits())`.
319 ///
320 /// # Panics
321 /// Panics if `n` is even.
322 ///
323 /// # Examples
324 /// See [here](super::kronecker_symbol#legendre_symbol).
325 #[inline]
326 fn legendre_symbol(self, n: $u) -> i8 {
327 self.jacobi_symbol(n)
328 }
329 }
330
331 impl LegendreSymbol<$s> for $s {
332 /// Computes the Legendre symbol of two numbers.
333 ///
334 /// This implementation is identical to that of [`JacobiSymbol`], since there is no
335 /// computational benefit to requiring that the denominator be prime.
336 ///
337 /// $$
338 /// f(x, y) = \left ( \frac{x}{y} \right ).
339 /// $$
340 ///
341 /// # Worst-case complexity
342 /// $T(n) = O(n^2)$
343 ///
344 /// $M(n) = O(n)$
345 ///
346 /// where $T$ is time, $M$ is additional memory, and $n$ is
347 /// `max(self.significant_bits(), other.significant_bits())`.
348 ///
349 /// # Panics
350 /// Panics if `n` is even or negative.
351 ///
352 /// # Examples
353 /// See [here](super::kronecker_symbol#legendre_symbol).
354 #[inline]
355 fn legendre_symbol(self, n: $s) -> i8 {
356 self.jacobi_symbol(n)
357 }
358 }
359
360 impl JacobiSymbol<$s> for $s {
361 /// Computes the Jacobi symbol of two numbers.
362 ///
363 /// $$
364 /// f(x, y) = \left ( \frac{x}{y} \right ).
365 /// $$
366 ///
367 /// # Worst-case complexity
368 /// $T(n) = O(n^2)$
369 ///
370 /// $M(n) = O(n)$
371 ///
372 /// where $T$ is time, $M$ is additional memory, and $n$ is
373 /// `max(self.significant_bits(), other.significant_bits())`.
374 ///
375 /// # Panics
376 /// Panics if `n` is even.
377 ///
378 /// # Examples
379 /// See [here](super::kronecker_symbol#jacobi_symbol).
380 #[inline]
381 fn jacobi_symbol(self, n: $s) -> i8 {
382 jacobi_symbol_signed::<$u, $s>(self, n)
383 }
384 }
385
386 impl KroneckerSymbol<$u> for $u {
387 /// Computes the Kronecker symbol of two numbers.
388 ///
389 /// $$
390 /// f(x, y) = \left ( \frac{x}{y} \right ).
391 /// $$
392 ///
393 /// # Worst-case complexity
394 /// $T(n) = O(n^2)$
395 ///
396 /// $M(n) = O(n)$
397 ///
398 /// where $T$ is time, $M$ is additional memory, and $n$ is
399 /// `max(self.significant_bits(), other.significant_bits())`.
400 ///
401 /// # Examples
402 /// See [here](super::kronecker_symbol#kronecker_symbol).
403 #[inline]
404 fn kronecker_symbol(self, n: $u) -> i8 {
405 kronecker_symbol_unsigned(self, n)
406 }
407 }
408
409 impl KroneckerSymbol<$s> for $s {
410 /// Computes the Kronecker symbol of two numbers.
411 ///
412 /// $$
413 /// f(x, y) = \left ( \frac{x}{y} \right ).
414 /// $$
415 ///
416 /// # Worst-case complexity
417 /// $T(n) = O(n^2)$
418 ///
419 /// $M(n) = O(n)$
420 ///
421 /// where $T$ is time, $M$ is additional memory, and $n$ is
422 /// `max(self.significant_bits(), other.significant_bits())`.
423 ///
424 /// # Examples
425 /// See [here](super::kronecker_symbol#kronecker_symbol).
426 #[inline]
427 fn kronecker_symbol(self, n: $s) -> i8 {
428 kronecker_symbol_signed::<$u, $s>(self, n)
429 }
430 }
431 };
432}
433apply_to_unsigned_signed_pairs!(impl_symbols);
434
435macro_rules! impl_jacobi_symbol_unsigned {
436 ($u:ident) => {
437 /// Computes the Jacobi symbol of two numbers.
438 ///
439 /// $$
440 /// f(x, y) = \left ( \frac{x}{y} \right ).
441 /// $$
442 ///
443 /// # Worst-case complexity
444 /// $T(n) = O(n^2)$
445 ///
446 /// $M(n) = O(n)$
447 ///
448 /// where $T$ is time, $M$ is additional memory, and $n$ is `max(self.significant_bits(),
449 /// other.significant_bits())`.
450 ///
451 /// # Panics
452 /// Panics if `n` is even or negative.
453 ///
454 /// # Examples
455 /// See [here](super::kronecker_symbol#jacobi_symbol).
456 impl JacobiSymbol<$u> for $u {
457 #[inline]
458 fn jacobi_symbol(self, n: $u) -> i8 {
459 jacobi_symbol_unsigned_simple(self, n)
460 }
461 }
462 };
463}
464impl_jacobi_symbol_unsigned!(u8);
465impl_jacobi_symbol_unsigned!(u16);
466impl_jacobi_symbol_unsigned!(u32);
467impl_jacobi_symbol_unsigned!(u64);
468impl_jacobi_symbol_unsigned!(usize);
469
470impl JacobiSymbol<u128> for u128 {
471 /// Computes the Jacobi symbol of two `u128`s.
472 ///
473 /// $$
474 /// f(x, y) = \left ( \frac{x}{y} \right ).
475 /// $$
476 ///
477 /// # Worst-case complexity
478 /// $T(n) = O(n^2)$
479 ///
480 /// $M(n) = O(n)$
481 ///
482 /// where $T$ is time, $M$ is additional memory, and $n$ is `max(self.significant_bits(),
483 /// other.significant_bits())`.
484 ///
485 /// # Examples
486 /// See [here](super::kronecker_symbol#jacobi_symbol).
487 #[inline]
488 fn jacobi_symbol(self, n: u128) -> i8 {
489 let (x_1, x_0) = self.split_in_half();
490 let (y_1, y_0) = n.split_in_half();
491 jacobi_symbol_unsigned_double_fast_2(x_1, x_0, y_1, y_0)
492 }
493}