malachite_base/num/arithmetic/mod_div.rs
1// Copyright © 2026 Mikhail Hogrefe
2//
3// Uses code adopted from the FLINT Library.
4//
5// Copyright © 2009, 2015 William Hart
6//
7// Copyright © 2019 Daniel Schultz
8//
9// This file is part of Malachite.
10//
11// Malachite is free software: you can redistribute it and/or modify it under the terms of the GNU
12// Lesser General Public License (LGPL) as published by the Free Software Foundation; either version
13// 3 of the License, or (at your option) any later version. See <https://www.gnu.org/licenses/>.
14
15use crate::num::arithmetic::traits::ModDiv;
16use crate::num::basic::signeds::PrimitiveSigned;
17use crate::num::basic::unsigneds::PrimitiveUnsigned;
18use crate::num::conversion::traits::WrappingFrom;
19
20// Computes `(gcd(x, y), s)`, where `s < y` and `sx ≡ gcd(x, y) mod y`. `x` must be reduced mod
21// `y`.
22//
23// This is n_gcdinv from ulong_extras/gcdinv.c, FLINT 3.6.0, where the GCD is returned along with
24// the cofactor.
25crate_test_fn! {gcdinv<
26 U: WrappingFrom<S> + PrimitiveUnsigned,
27 S: PrimitiveSigned + WrappingFrom<U>,
28>(
29 x: U,
30 y: U,
31) -> (U, U) {
32 assert!(x < y, "x must be reduced mod y, but {x} >= {y}");
33 let mut v1 = S::ZERO;
34 let mut v2 = S::ONE;
35 let mut r = x;
36 let mut x = y;
37 let mut d;
38 let mut t2;
39 // y and x both have their highest bit set
40 if (x & r).get_highest_bit() {
41 d = x - r;
42 t2 = v2;
43 x = r;
44 v2 = v1 - v2;
45 v1 = t2;
46 r = d;
47 }
48 // second value has its second-highest bit set
49 while r.get_bit(U::WIDTH - 2) {
50 d = x - r;
51 r = if d < r {
52 // quot = 1
53 t2 = v2;
54 x = r;
55 v2 = v1 - v2;
56 v1 = t2;
57 d
58 } else if d < (r << 1) {
59 // quot = 2
60 x = r;
61 t2 = v2;
62 v2 = v1 - (v2 << 1);
63 v1 = t2;
64 d - x
65 } else {
66 // quot = 3
67 x = r;
68 t2 = v2;
69 v2 = v1 - S::wrapping_from(3) * v2;
70 v1 = t2;
71 d - (x << 1)
72 };
73 }
74 while r != U::ZERO {
75 // overflow not possible, top 2 bits of r not set
76 r = if x < (r << 2) {
77 // quot < 4
78 d = x - r;
79 if d < r {
80 // quot = 1
81 t2 = v2;
82 x = r;
83 v2 = v1 - v2;
84 v1 = t2;
85 d
86 } else if d < (r << 1) {
87 // quot = 2
88 x = r;
89 t2 = v2;
90 v2 = v1.wrapping_sub(v2 << 1);
91 v1 = t2;
92 d - x
93 } else {
94 // quot = 3
95 x = r;
96 t2 = v2;
97 v2 = v1.wrapping_sub(S::wrapping_from(3).wrapping_mul(v2));
98 v1 = t2;
99 d.wrapping_sub(x << 1)
100 }
101 } else {
102 let (quot, rem) = x.div_rem(r);
103 x = r;
104 t2 = v2;
105 v2 = v1.wrapping_sub(S::wrapping_from(quot).wrapping_mul(v2));
106 v1 = t2;
107 rem
108 };
109 }
110 let mut s = U::wrapping_from(v1);
111 if v1 < S::ZERO {
112 s.wrapping_add_assign(y);
113 }
114 (x, s)
115}}
116
117// Computes a quotient of `b` and `c` modulo `m`: a `q` such that `qc ≡ b mod m`. `b` and `c` must
118// be reduced mod `m`.
119//
120// This is fmpz_mod_divides from fmpz_mod/divides.c, FLINT 3.6.0, where b and c are word-sized and
121// reduced mod the modulus, and the quotient is returned as an Option.
122private_test_fn! {mod_div_unsigned<
123 U: WrappingFrom<S> + PrimitiveUnsigned,
124 S: PrimitiveSigned + WrappingFrom<U>,
125>(
126 b: U,
127 c: U,
128 m: U,
129) -> Option<U> {
130 assert!(b < m, "b must be reduced mod m, but {b} >= {m}");
131 assert!(c < m, "c must be reduced mod m, but {c} >= {m}");
132 if c == U::ZERO {
133 return if b == U::ZERO {
134 Some(U::ZERO)
135 } else {
136 None
137 };
138 }
139 if b == U::ZERO {
140 return Some(U::ZERO);
141 }
142 // b and c are both nonzero now, so m >= 2. Solve g = cx + my, where g = gcd(c, m).
143 let (g, x) = gcdinv::<U, S>(c, m);
144 let (q, r) = b.div_rem(g);
145 if r == U::ZERO {
146 Some(q.mod_mul(x, m))
147 } else {
148 None
149 }
150}}
151
152macro_rules! impl_mod_div {
153 ($u:ident, $s:ident) => {
154 impl ModDiv<$u> for $u {
155 type Output = $u;
156
157 /// Divides a number by another number modulo a third number $m$, returning `None` if no
158 /// quotient exists. The inputs must be already reduced modulo $m$.
159 ///
160 /// A quotient exists if and only if $\gcd(y, m)$ divides $x$. If $y$ is not invertible
161 /// modulo $m$, the quotient is not unique; all quotients differ by multiples of
162 /// $m/\gcd(y, m)$, and this function returns one of them.
163 ///
164 /// $f(x, y, m) = \operatorname{Some}(q)$, where $x, y, q < m$ and $qy \equiv x \mod m$,
165 /// if such a $q$ exists.
166 ///
167 /// # Worst-case complexity
168 /// $T(n) = O(n)$
169 ///
170 /// $M(n) = O(1)$
171 ///
172 /// where $T$ is time, $M$ is additional memory, and $n$ is `m.significant_bits()`: the
173 /// extended Euclidean algorithm on words performs $O(n)$ iterations of constant-cost
174 /// word operations, with no allocation.
175 ///
176 /// # Panics
177 /// Panics if `self` or `other` are greater than or equal to `m`.
178 ///
179 /// # Examples
180 /// See [here](super::mod_div#mod_div).
181 #[inline]
182 fn mod_div(self, other: $u, m: $u) -> Option<$u> {
183 mod_div_unsigned::<$u, $s>(self, other, m)
184 }
185 }
186 };
187}
188apply_to_unsigned_signed_pairs!(impl_mod_div);