Skip to main content

malachite_base/num/arithmetic/
mod_inverse.rs

1// Copyright © 2026 Mikhail Hogrefe
2//
3// This file is part of Malachite.
4//
5// Malachite is free software: you can redistribute it and/or modify it under the terms of the GNU
6// Lesser General Public License (LGPL) as published by the Free Software Foundation; either version
7// 3 of the License, or (at your option) any later version. See <https://www.gnu.org/licenses/>.
8
9use crate::num::arithmetic::mod_div::gcdinv;
10use crate::num::arithmetic::traits::ModInverse;
11use crate::num::basic::signeds::PrimitiveSigned;
12use crate::num::basic::unsigneds::PrimitiveUnsigned;
13use crate::num::conversion::traits::WrappingFrom;
14
15// The modular inverse is unique, so filtering the cofactor from `gcdinv` on the GCD being 1
16// produces the same value as any other algorithm.
17private_test_fn! {mod_inverse_binary<
18    U: WrappingFrom<S> + PrimitiveUnsigned,
19    S: PrimitiveSigned + WrappingFrom<U>,
20>(
21    x: U,
22    m: U,
23) -> Option<U> {
24    assert_ne!(x, U::ZERO);
25    assert!(x < m, "x must be reduced mod m, but {x} >= {m}");
26    let (gcd, inverse) = gcdinv::<U, S>(x, m);
27    if gcd == U::ONE {
28        Some(inverse)
29    } else {
30        None
31    }
32}}
33
34macro_rules! impl_mod_inverse {
35    ($u:ident, $s:ident) => {
36        impl ModInverse<$u> for $u {
37            type Output = $u;
38
39            /// Computes the multiplicative inverse of a number modulo another number $m$. The input
40            /// must be already reduced modulo $m$.
41            ///
42            /// Returns `None` if $x$ and $m$ are not coprime.
43            ///
44            /// $f(x, m) = y$, where $x, y < m$, $\gcd(x, y) = 1$, and $xy \equiv 1 \mod m$.
45            ///
46            /// # Worst-case complexity
47            /// $T(n) = O(n)$
48            ///
49            /// $M(n) = O(1)$
50            ///
51            /// where $T$ is time, $M$ is additional memory, and $n$ is
52            /// `max(self.significant_bits(), m.significant_bits())`: the extended Euclidean
53            /// algorithm on words performs $O(n)$ iterations of constant-cost word operations, with
54            /// no allocation.
55            ///
56            /// # Panics
57            /// Panics if `self` is greater than or equal to `m`.
58            ///
59            /// # Examples
60            /// See [here](super::mod_inverse#mod_inverse).
61            #[inline]
62            fn mod_inverse(self, m: $u) -> Option<$u> {
63                mod_inverse_binary::<$u, $s>(self, m)
64            }
65        }
66    };
67}
68apply_to_unsigned_signed_pairs!(impl_mod_inverse);