malachite_base/num/arithmetic/mod_power_of_2_inverse.rs
1// Copyright © 2025 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::traits::ModPowerOf2Inverse;
10use crate::num::basic::unsigneds::PrimitiveUnsigned;
11
12// Uses Newton's method, as described by Colin Plumb in
13// https://groups.google.com/g/sci.crypt/c/UI-UMbUnYGk/m/hX2-wQVyE3oJ.
14pub_test! {mod_power_of_2_inverse_fast<T: PrimitiveUnsigned>(x: T, pow: u64) -> Option<T> {
15 assert_ne!(x, T::ZERO);
16 assert!(pow <= T::WIDTH);
17 assert!(x.significant_bits() <= pow, "x must be reduced mod 2^pow, but {x} >= 2^{pow}");
18 if x.even() {
19 return None;
20 } else if x == T::ONE {
21 return Some(T::ONE);
22 }
23 let mut small_pow = 2;
24 let mut inverse = x.mod_power_of_2(2);
25 while small_pow < pow {
26 small_pow <<= 1;
27 if small_pow > pow {
28 small_pow = pow;
29 }
30 // inverse <- inverse * (2 - inverse * x) mod 2^small_pow
31 inverse.mod_power_of_2_mul_assign(
32 T::TWO.mod_power_of_2_sub(
33 inverse.mod_power_of_2_mul(x.mod_power_of_2(small_pow), small_pow),
34 small_pow,
35 ),
36 small_pow,
37 );
38 }
39 Some(inverse)
40}}
41
42macro_rules! impl_mod_power_of_2_inverse {
43 ($u:ident) => {
44 impl ModPowerOf2Inverse for $u {
45 type Output = $u;
46
47 /// Computes the multiplicative inverse of a number modulo $2^k$. The input must be
48 /// already reduced modulo $2^k$.
49 ///
50 /// Returns `None` if $x$ is even.
51 ///
52 /// $f(x, k) = y$, where $x, y < 2^k$, $x$ is odd, and $xy \equiv 1 \mod 2^k$.
53 ///
54 /// # Worst-case complexity
55 /// $T(n) = O(n)$
56 ///
57 /// $M(n) = O(1)$
58 ///
59 /// where $T$ is time, $M$ is additional memory, and $n$ is `pow`.
60 ///
61 /// # Panics
62 /// Panics if `pow` is greater than `Self::WIDTH`, if `self` is zero, or if `self` is
63 /// greater than or equal to $2^k$.
64 ///
65 /// # Examples
66 /// See [here](super::mod_power_of_2_inverse#mod_power_of_2_inverse).
67 #[inline]
68 fn mod_power_of_2_inverse(self, pow: u64) -> Option<$u> {
69 mod_power_of_2_inverse_fast(self, pow)
70 }
71 }
72 };
73}
74apply_to_unsigneds!(impl_mod_power_of_2_inverse);