1use subtle::{Choice, ConditionallySelectable};
5
6use crate::{
7 primitives::{addhilo, mulhilo},
8 ConstChoice, Limb, NonZero, Uint, WideWord, Word,
9};
10
11#[cfg(target_pointer_width = "32")]
13pub const fn reciprocal(d: Word) -> Word {
14 debug_assert!(d >= (1 << (Word::BITS - 1)));
15
16 let d0 = d & 1;
17 let d10 = d >> 22;
18 let d21 = (d >> 11) + 1;
19 let d31 = (d >> 1) + d0;
20 let v0 = short_div((1 << 24) - (1 << 14) + (1 << 9), 24, d10, 10);
21 let (hi, _lo) = mulhilo(v0 * v0, d21);
22 let v1 = (v0 << 4) - hi - 1;
23
24 debug_assert!(mulhilo(v1, d31).0 == (1 << 16) - 1);
26 let e = Word::MAX - v1.wrapping_mul(d31) + 1 + (v1 >> 1) * d0;
27
28 let (hi, _lo) = mulhilo(v1, e);
29 let v2 = (v1 << 15).wrapping_add(hi >> 1);
33
34 let x = v2.wrapping_add(1);
38 let (hi, _lo) = mulhilo(x, d);
39 let hi = ConstChoice::from_u32_nonzero(x).select_word(d, hi);
40
41 v2.wrapping_sub(hi).wrapping_sub(d)
42}
43
44#[cfg(target_pointer_width = "64")]
46pub const fn reciprocal(d: Word) -> Word {
47 debug_assert!(d >= (1 << (Word::BITS - 1)));
48
49 let d0 = d & 1;
50 let d9 = d >> 55;
51 let d40 = (d >> 24) + 1;
52 let d63 = (d >> 1) + d0;
53 let v0 = short_div((1 << 19) - 3 * (1 << 8), 19, d9 as u32, 9) as u64;
54 let v1 = (v0 << 11) - ((v0 * v0 * d40) >> 40) - 1;
55 let v2 = (v1 << 13) + ((v1 * ((1 << 60) - v1 * d40)) >> 47);
56
57 debug_assert!(mulhilo(v2, d63).0 == (1 << 32) - 1);
59 let e = Word::MAX - v2.wrapping_mul(d63) + 1 + (v2 >> 1) * d0;
60
61 let (hi, _lo) = mulhilo(v2, e);
62 let v3 = (v2 << 31).wrapping_add(hi >> 1);
63
64 let x = v3.wrapping_add(1);
68 let (hi, _lo) = mulhilo(x, d);
69 let hi = ConstChoice::from_word_nonzero(x).select_word(d, hi);
70
71 v3.wrapping_sub(hi).wrapping_sub(d)
72}
73
74#[inline]
76const fn lt(a: u32, b: u32) -> u32 {
77 let bit = (((!a) & b) | (((!a) | b) & (a.wrapping_sub(b)))) >> (u32::BITS - 1);
79 bit.wrapping_neg()
80}
81
82#[inline(always)]
84const fn select(a: u32, b: u32, c: u32) -> u32 {
85 a ^ (c & (a ^ b))
87}
88
89#[inline(always)]
92const fn short_div(dividend: u32, dividend_bits: u32, divisor: u32, divisor_bits: u32) -> u32 {
93 let mut dividend = dividend;
103 let mut divisor = divisor << (dividend_bits - divisor_bits);
104 let mut quotient: u32 = 0;
105 let mut i = dividend_bits - divisor_bits + 1;
106
107 while i > 0 {
108 i -= 1;
109 let bit = lt(dividend, divisor);
110 dividend = select(dividend.wrapping_sub(divisor), dividend, bit);
111 divisor >>= 1;
112 let inv_bit = !bit;
113 quotient |= (inv_bit >> (u32::BITS - 1)) << i;
114 }
115
116 quotient
117}
118
119#[inline(always)]
122pub(crate) const fn div2by1(u1: Word, u0: Word, reciprocal: &Reciprocal) -> (Word, Word) {
123 let d = reciprocal.divisor_normalized;
124
125 debug_assert!(d >= (1 << (Word::BITS - 1)));
126 debug_assert!(u1 < d);
127
128 let (q1, q0) = mulhilo(reciprocal.reciprocal, u1);
129 let (q1, q0) = addhilo(q1, q0, u1, u0);
130 let q1 = q1.wrapping_add(1);
131 let r = u0.wrapping_sub(q1.wrapping_mul(d));
132
133 let r_gt_q0 = ConstChoice::from_word_lt(q0, r);
134 let q1 = r_gt_q0.select_word(q1, q1.wrapping_sub(1));
135 let r = r_gt_q0.select_word(r, r.wrapping_add(d));
136
137 debug_assert!(r < d || q1 < Word::MAX);
141 let r_ge_d = ConstChoice::from_word_le(d, r);
142 let q1 = r_ge_d.select_word(q1, q1.wrapping_add(1));
143 let r = r_ge_d.select_word(r, r.wrapping_sub(d));
144
145 (q1, r)
146}
147
148#[inline(always)]
154pub(crate) const fn div3by2(
155 u2: Word,
156 u1: Word,
157 u0: Word,
158 v1_reciprocal: &Reciprocal,
159 v0: Word,
160) -> Word {
161 debug_assert!(v1_reciprocal.shift == 0);
162 debug_assert!(u2 <= v1_reciprocal.divisor_normalized);
163
164 let q_maxed = ConstChoice::from_word_eq(u2, v1_reciprocal.divisor_normalized);
168 let (mut quo, rem) = div2by1(q_maxed.select_word(u2, 0), u1, v1_reciprocal);
169 quo = q_maxed.select_word(quo, Word::MAX);
172 let mut rem = q_maxed.select_wide_word(rem as WideWord, (u2 as WideWord) + (u1 as WideWord));
173
174 let mut i = 0;
175 while i < 2 {
176 let qy = (quo as WideWord) * (v0 as WideWord);
177 let rx = (rem << Word::BITS) | (u0 as WideWord);
178 let done = ConstChoice::from_word_nonzero((rem >> Word::BITS) as Word)
180 .or(ConstChoice::from_wide_word_le(qy, rx));
181 quo = done.select_word(quo.wrapping_sub(1), quo);
182 rem = done.select_wide_word(rem + (v1_reciprocal.divisor_normalized as WideWord), rem);
183 i += 1;
184 }
185
186 quo
187}
188
189#[derive(Copy, Clone, Debug, PartialEq, Eq)]
191pub struct Reciprocal {
192 divisor_normalized: Word,
193 shift: u32,
194 reciprocal: Word,
195}
196
197impl Reciprocal {
198 pub const fn new(divisor: NonZero<Limb>) -> Self {
201 let divisor = divisor.0;
202
203 let shift = divisor.0.leading_zeros();
205
206 let divisor_normalized = divisor.0 << shift;
208
209 Self {
210 divisor_normalized,
211 shift,
212 reciprocal: reciprocal(divisor_normalized),
213 }
214 }
215
216 pub const fn default() -> Self {
222 Self {
223 divisor_normalized: Word::MAX,
224 shift: 0,
225 reciprocal: 1,
228 }
229 }
230
231 #[cfg(feature = "alloc")]
232 pub(crate) const fn divisor(&self) -> NonZero<Limb> {
233 NonZero(Limb(self.divisor_normalized >> self.shift))
234 }
235
236 pub const fn shift(&self) -> u32 {
238 self.shift
239 }
240}
241
242impl ConditionallySelectable for Reciprocal {
243 fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
244 Self {
245 divisor_normalized: Word::conditional_select(
246 &a.divisor_normalized,
247 &b.divisor_normalized,
248 choice,
249 ),
250 shift: u32::conditional_select(&a.shift, &b.shift, choice),
251 reciprocal: Word::conditional_select(&a.reciprocal, &b.reciprocal, choice),
252 }
253 }
254}
255
256impl Default for Reciprocal {
259 fn default() -> Self {
260 Self::default()
261 }
262}
263
264#[inline(always)]
267pub(crate) const fn div_rem_limb_with_reciprocal<const L: usize>(
268 u: &Uint<L>,
269 reciprocal: &Reciprocal,
270) -> (Uint<L>, Limb) {
271 let (u_shifted, u_hi) = u.shl_limb(reciprocal.shift);
272 let mut r = u_hi.0;
273 let mut q = [Limb::ZERO; L];
274
275 let mut j = L;
276 while j > 0 {
277 j -= 1;
278 let (qj, rj) = div2by1(r, u_shifted.as_limbs()[j].0, reciprocal);
279 q[j] = Limb(qj);
280 r = rj;
281 }
282 (Uint::<L>::new(q), Limb(r >> reciprocal.shift))
283}
284
285#[inline(always)]
287pub(crate) const fn rem_limb_with_reciprocal<const L: usize>(
288 u: &Uint<L>,
289 reciprocal: &Reciprocal,
290) -> Limb {
291 let (u_shifted, u_hi) = u.shl_limb(reciprocal.shift);
292 let mut r = u_hi.0;
293
294 let mut j = L;
295 while j > 0 {
296 j -= 1;
297 let (_, rj) = div2by1(r, u_shifted.as_limbs()[j].0, reciprocal);
298 r = rj;
299 }
300 Limb(r >> reciprocal.shift)
301}
302
303#[inline(always)]
305pub(crate) const fn rem_limb_with_reciprocal_wide<const L: usize>(
306 lo_hi: (&Uint<L>, &Uint<L>),
307 reciprocal: &Reciprocal,
308) -> Limb {
309 let (lo_shifted, carry) = lo_hi.0.shl_limb(reciprocal.shift);
310 let (mut hi_shifted, xhi) = lo_hi.1.shl_limb(reciprocal.shift);
311 hi_shifted.limbs[0].0 |= carry.0;
312 let mut r = xhi.0;
313
314 let mut j = L;
315 while j > 0 {
316 j -= 1;
317 let (_, rj) = div2by1(r, hi_shifted.as_limbs()[j].0, reciprocal);
318 r = rj;
319 }
320 j = L;
321 while j > 0 {
322 j -= 1;
323 let (_, rj) = div2by1(r, lo_shifted.as_limbs()[j].0, reciprocal);
324 r = rj;
325 }
326 Limb(r >> reciprocal.shift)
327}
328
329#[inline(always)]
331pub(crate) const fn mul_rem(a: Limb, b: Limb, d: NonZero<Limb>) -> Limb {
332 let rec = Reciprocal::new(d);
333 let (hi, lo) = mulhilo(a.0, b.0);
334 rem_limb_with_reciprocal(&Uint::from_words([lo, hi]), &rec)
335}
336
337#[cfg(test)]
338mod tests {
339 use super::{div2by1, Reciprocal};
340 use crate::{Limb, NonZero, Word};
341 #[test]
342 fn div2by1_overflow() {
343 let r = Reciprocal::new(NonZero::new(Limb(Word::MAX - 1)).unwrap());
347 assert_eq!(
348 div2by1(Word::MAX - 2, Word::MAX - 63, &r),
349 (Word::MAX, Word::MAX - 65)
350 );
351 }
352}