Skip to main content

malachite_nz/natural/arithmetic/
mod_power_of_2_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::integer::conversion::to_twos_complement_limbs::limbs_twos_complement_in_place;
10use crate::natural::InnerNatural::{Large, Small};
11use crate::natural::arithmetic::add::limbs_slice_add_limb_in_place;
12use crate::natural::arithmetic::mod_power_of_2::limbs_slice_mod_power_of_2_in_place;
13use crate::natural::arithmetic::mul::mul_low::limbs_mul_low_same_length;
14use crate::natural::{Natural, bit_to_limb_count_ceiling};
15use crate::platform::Limb;
16use malachite_base::num::arithmetic::traits::{ModPowerOf2Inverse, Parity};
17use malachite_base::num::basic::integers::PrimitiveInt;
18use malachite_base::num::basic::traits::One;
19use malachite_base::num::logic::traits::SignificantBits;
20
21// - out should be just long enough for `pow` bits.
22// - xs should have the same length as out.
23// - scratch should be at least twice as long as out.
24// - out should be filled with zeros.
25fn limbs_mod_power_of_2_inverse(out: &mut [Limb], xs: &[Limb], pow: u64, scratch: &mut [Limb]) {
26    let len = out.len();
27    split_into_chunks_mut!(scratch, len, [scratch_0, scratch_1], _unused);
28    let mut limb_pow = 1;
29    out[0] = xs[0].mod_power_of_2_inverse(Limb::WIDTH).unwrap();
30    while limb_pow < len {
31        limb_pow <<= 1;
32        if limb_pow > len {
33            limb_pow = len;
34        }
35        let out_lo = &mut out[..limb_pow];
36        let scratch_0_lo = &mut scratch_0[..limb_pow];
37        let scratch_1_lo = &mut scratch_1[..limb_pow];
38        limbs_mul_low_same_length(scratch_0_lo, out_lo, &xs[..limb_pow]);
39        limbs_twos_complement_in_place(scratch_0_lo);
40        limbs_slice_add_limb_in_place(scratch_0_lo, 2);
41        limbs_mul_low_same_length(scratch_1_lo, scratch_0_lo, out_lo);
42        out_lo.copy_from_slice(scratch_1_lo);
43    }
44    limbs_slice_mod_power_of_2_in_place(out, pow);
45}
46
47#[allow(clippy::unnecessary_wraps)]
48fn mod_power_of_2_inverse_helper(xs: &[Limb], pow: u64) -> Option<Natural> {
49    let len = xs.len();
50    let mut big_scratch = vec![0; len * 3];
51    let (out, scratch) = big_scratch.split_at_mut(len);
52    limbs_mod_power_of_2_inverse(out, xs, pow, scratch);
53    big_scratch.truncate(len);
54    Some(Natural::from_owned_limbs_asc(big_scratch))
55}
56
57impl ModPowerOf2Inverse for Natural {
58    type Output = Self;
59
60    /// Computes the multiplicative inverse of a [`Natural`] modulo $2^k$. The input must be already
61    /// reduced modulo $2^k$. The [`Natural`] is taken by value.
62    ///
63    /// Returns `None` if $x$ is even.
64    ///
65    /// $f(x, k) = y$, where $x, y < 2^k$, $x$ is odd, and $xy \equiv 1 \mod 2^k$.
66    ///
67    /// # Worst-case complexity
68    /// $T(n) = O(n \log n \log\log n)$
69    ///
70    /// $M(n) = O(n \log n)$
71    ///
72    /// where $T$ is time, $M$ is additional memory, and $n$ is `pow`.
73    ///
74    /// # Panics
75    /// Panics if `self` is 0 or if `self` is greater than or equal to $2^k$.
76    ///
77    /// # Examples
78    /// ```
79    /// use malachite_base::num::arithmetic::traits::ModPowerOf2Inverse;
80    /// use malachite_nz::natural::Natural;
81    ///
82    /// assert_eq!(
83    ///     Natural::from(3u32).mod_power_of_2_inverse(8),
84    ///     Some(Natural::from(171u32))
85    /// );
86    /// assert_eq!(Natural::from(4u32).mod_power_of_2_inverse(8), None);
87    /// ```
88    fn mod_power_of_2_inverse(self, pow: u64) -> Option<Self> {
89        assert_ne!(self, 0u32);
90        assert!(
91            self.significant_bits() <= pow,
92            "self must be reduced mod 2^pow, but {self} >= 2^{pow}"
93        );
94        match (self, pow) {
95            (Self::ONE, _) => Some(Self::ONE),
96            (x, _) if x.even() => None,
97            (Self(Small(x)), pow) if pow <= Limb::WIDTH => {
98                x.mod_power_of_2_inverse(pow).map(Self::from)
99            }
100            (Self(Small(x)), pow) => {
101                let len = bit_to_limb_count_ceiling(pow);
102                let mut xs = vec![0; len];
103                xs[0] = x;
104                mod_power_of_2_inverse_helper(&xs, pow)
105            }
106            (Self(Large(mut xs)), pow) => {
107                let len = bit_to_limb_count_ceiling(pow);
108                xs.resize(len, 0);
109                mod_power_of_2_inverse_helper(&xs, pow)
110            }
111        }
112    }
113}
114
115impl ModPowerOf2Inverse for &Natural {
116    type Output = Natural;
117
118    /// Computes the multiplicative inverse of a [`Natural`] modulo $2^k$. The input must be already
119    /// reduced modulo $2^k$. The [`Natural`] is taken by reference.
120    ///
121    /// Returns `None` if $x$ is even.
122    ///
123    /// $f(x, k) = y$, where $x, y < 2^k$, $x$ is odd, and $xy \equiv 1 \mod 2^k$.
124    ///
125    /// # Worst-case complexity
126    /// $T(n) = O(n \log n \log\log n)$
127    ///
128    /// $M(n) = O(n \log n)$
129    ///
130    /// where $T$ is time, $M$ is additional memory, and $n$ is `pow`.
131    ///
132    /// # Panics
133    /// Panics if `self` is 0 or if `self` is greater than or equal to $2^k$.
134    ///
135    /// # Examples
136    /// ```
137    /// use malachite_base::num::arithmetic::traits::ModPowerOf2Inverse;
138    /// use malachite_nz::natural::Natural;
139    ///
140    /// assert_eq!(
141    ///     (&Natural::from(3u32)).mod_power_of_2_inverse(8),
142    ///     Some(Natural::from(171u32))
143    /// );
144    /// assert_eq!((&Natural::from(4u32)).mod_power_of_2_inverse(8), None);
145    /// ```
146    fn mod_power_of_2_inverse(self, pow: u64) -> Option<Natural> {
147        assert_ne!(*self, 0u32);
148        assert!(
149            self.significant_bits() <= pow,
150            "self must be reduced mod 2^pow, but {self} >= 2^{pow}"
151        );
152        match (self, pow) {
153            (&Natural::ONE, _) => Some(Natural::ONE),
154            (x, _) if x.even() => None,
155            (Natural(Small(x)), pow) if pow <= Limb::WIDTH => {
156                x.mod_power_of_2_inverse(pow).map(Natural::from)
157            }
158            (Natural(Small(x)), pow) => {
159                let mut xs = vec![0; bit_to_limb_count_ceiling(pow)];
160                xs[0] = *x;
161                mod_power_of_2_inverse_helper(&xs, pow)
162            }
163            (Natural(Large(xs)), pow) => {
164                let mut xs = xs.clone();
165                xs.resize(bit_to_limb_count_ceiling(pow), 0);
166                mod_power_of_2_inverse_helper(&xs, pow)
167            }
168        }
169    }
170}