malachite_nz/natural/arithmetic/
mod_power_of_2_inverse.rs1use 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
21fn 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 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 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}