Skip to main content

crypto_bigint/uint/ref_type/
div.rs

1//! In-place integer division
2//!
3//! Based on Section 4.3.1, of The Art of Computer Programming, Volume 2, by Donald E. Knuth.
4//! Further explanation at <https://janmr.com/blog/2014/04/basic-multiple-precision-long-division/>
5
6use super::UintRef;
7use crate::{
8    Choice, Limb, NonZero,
9    div_limb::{Reciprocal, div2by1, div3by2},
10    primitives::u32_min,
11    word,
12};
13
14// TODO(tarcieri): make `rhs` into `NonZeroUintRef` then make currently panicking functions `pub`
15impl UintRef {
16    /// Computes `self` / `rhs`, returning the quotient in `self` and the remainder in `rhs`.
17    ///
18    /// # Panics
19    /// If the divisor is zero.
20    #[inline(always)]
21    #[allow(clippy::integer_division_remainder_used, reason = "needs triage")]
22    pub(crate) const fn div_rem(&mut self, rhs: &mut Self) {
23        let (x, y) = (self, rhs);
24
25        // Short circuit for single-word divisor
26        if y.nlimbs() == 1 {
27            y.limbs[0] = x.div_rem_limb(y.limbs[0].to_nz().expect_copied("zero divisor"));
28            return;
29        }
30
31        // Compute the size of the divisor
32        let ybits = y.bits();
33        assert!(ybits > 0, "zero divisor");
34        let ywords = ybits.div_ceil(Limb::BITS);
35
36        // Shift the entire divisor such that the high bit is set
37        let yz = y.bits_precision() - ybits;
38        y.unbounded_shl_assign(yz);
39
40        // Shift the dividend to align the words
41        let lshift = yz % Limb::BITS;
42        let x_hi = x.shl_assign_limb(lshift);
43
44        Self::div_rem_shifted(x, x_hi, y, ywords);
45
46        x.unbounded_shr_assign_by_limbs(ywords - 1);
47        y.shr_assign_limb(lshift);
48    }
49
50    /// Computes `self` / `rhs`, returning the quotient in `self` and the remainder in `rhs`.
51    ///
52    /// This function operates in variable-time with respect to `rhs`. For a fixed divisor,
53    /// it operates in constant-time
54    ///
55    /// # Panics
56    /// If the divisor is zero.
57    #[allow(clippy::cast_possible_truncation)]
58    pub(crate) const fn div_rem_vartime(&mut self, rhs: &mut Self) {
59        let (x, y) = (self, rhs);
60        let xsize = x.nlimbs();
61        let ywords = y.bits_vartime().div_ceil(Limb::BITS) as usize;
62
63        match (xsize, ywords) {
64            (_, 0) => panic!("zero divisor"),
65            (0, _) => {
66                // If the quotient is empty, set the remainder to zero and return.
67                y.fill(Limb::ZERO);
68                return;
69            }
70            (_, 1) => {
71                // Perform limb division
72                let rem_limb = x.div_rem_limb(y.limbs[0].to_nz().expect_copied("zero divisor"));
73                y.fill(Limb::ZERO);
74                y.limbs[0] = rem_limb;
75                return;
76            }
77            _ if ywords > xsize => {
78                // Divisor is greater than dividend. Return zero and the dividend as the
79                // quotient and remainder
80                y.leading_mut(xsize).copy_from(x.leading(xsize));
81                y.trailing_mut(xsize).fill(Limb::ZERO);
82                x.fill(Limb::ZERO);
83                return;
84            }
85            _ => (),
86        }
87
88        x.div_rem_large_vartime(y.leading_mut(ywords));
89
90        // Shift the quotient to the low limbs within dividend
91        x.unbounded_shr_assign_by_limbs_vartime((ywords - 1) as u32);
92    }
93
94    /// Computes `x_lower_upper` % `rhs`, returning the remainder in `rhs`.
95    ///
96    /// The `x_lower_upper` tuple represents a wide integer. The size of `x_lower_upper.1` must be
97    /// at least as large as `rhs`. `x_lower_upper` is left in an indeterminate state.
98    ///
99    /// # Panics
100    /// If the divisor is zero.
101    #[inline(always)]
102    #[allow(clippy::integer_division_remainder_used, reason = "needs triage")]
103    pub(crate) const fn rem_wide(x_lower_upper: (&mut Self, &mut Self), rhs: &mut Self) {
104        let (x_lo, x) = x_lower_upper;
105        let y = rhs;
106
107        // Short circuit for single-word divisor
108        if y.nlimbs() == 1 {
109            let reciprocal = Reciprocal::new(y.limbs[0].to_nz().expect_copied("zero divisor"));
110            let carry = x.rem_limb_with_reciprocal(&reciprocal, Limb::ZERO);
111            y.limbs[0] = x_lo.rem_limb_with_reciprocal(&reciprocal, carry);
112            return;
113        }
114
115        // Compute the size of the divisor
116        let ybits = y.bits();
117        assert!(ybits > 0, "zero divisor");
118        let ywords = ybits.div_ceil(Limb::BITS);
119
120        // Shift the entire divisor such that the high bit is set
121        let yz = y.bits_precision() - ybits;
122        y.unbounded_shl_assign(yz);
123
124        // Shift the dividend to align the words
125        let lshift = yz % Limb::BITS;
126        let x_lo_carry = x_lo.shl_assign_limb(lshift);
127        let x_hi = x.shl_assign_limb(lshift);
128        x.limbs[0] = x.limbs[0].bitor(x_lo_carry);
129
130        // Perform the core division algorithm
131        Self::rem_wide_shifted((x_lo, x), x_hi, y, ywords);
132
133        // Unshift the remainder from the earlier adjustment
134        y.shr_assign_limb(lshift);
135    }
136
137    /// Computes `x_lower_upper` % `rhs`, returning the remainder in `rhs`.
138    ///
139    /// This function operates in variable-time with respect to `rhs`. For a fixed divisor,
140    /// it operates in constant-time.
141    ///
142    /// The `x_lower_upper` tuple represents a wide integer. The size of `x_lower_upper.1`
143    /// must be at least as large as `rhs`. `x_lower_upper` is left in an indeterminate state.
144    ///
145    /// # Panics
146    /// If the divisor is zero.
147    #[inline(always)]
148    #[allow(clippy::cast_possible_truncation)]
149    pub(crate) const fn rem_wide_vartime(x_lower_upper: (&mut Self, &mut Self), rhs: &mut Self) {
150        let (x_lo, x) = x_lower_upper;
151        let xsize = x.nlimbs();
152        let ysize = rhs.bits_vartime().div_ceil(Limb::BITS) as usize;
153        let y = rhs.leading_mut(ysize);
154
155        match (xsize, ysize) {
156            (_, 0) => panic!("zero divisor"),
157            (0, _) => {
158                // If the quotient is empty, set the remainder to zero and return.
159                y.fill(Limb::ZERO);
160                return;
161            }
162            (_, 1) => {
163                // Short circuit for single-word divisor
164                let reciprocal = Reciprocal::new(y.limbs[0].to_nz().expect_copied("zero divisor"));
165                y.fill(Limb::ZERO);
166                let carry = x.rem_limb_with_reciprocal(&reciprocal, Limb::ZERO);
167                y.limbs[0] = x_lo.rem_limb_with_reciprocal(&reciprocal, carry);
168                return;
169            }
170            _ if ysize > xsize => {
171                panic!("divisor too large");
172            }
173            _ => (),
174        }
175
176        let lshift = y.limbs[ysize - 1].leading_zeros();
177
178        // Shift divisor such that it has no leading zeros
179        // This means that div2by1 requires no extra shifts, and ensures that the high word >= b/2
180        y.shl_assign_limb_vartime(lshift);
181
182        // Shift the dividend to align the words
183        let x_lo_carry = x_lo.shl_assign_limb_vartime(lshift);
184        let mut x_hi = x.shl_assign_limb_vartime(lshift);
185        x.limbs[0] = x.limbs[0].bitor(x_lo_carry);
186
187        // Calculate a reciprocal from the highest word of the divisor
188        let reciprocal = Reciprocal::new(y.limbs[ysize - 1].to_nz().expect_copied("zero divisor"));
189
190        // Perform the core division algorithm
191        x_hi = Self::rem_wide_large_shifted(
192            (x_lo, x),
193            x_hi,
194            y,
195            ysize as u32,
196            reciprocal,
197            Choice::TRUE,
198        );
199
200        // Copy the remainder to the divisor
201        y.leading_mut(ysize - 1).copy_from(x.leading(ysize - 1));
202        y.limbs[ysize - 1] = x_hi;
203
204        // Unshift the remainder from the earlier adjustment
205        y.shr_assign_limb_vartime(lshift);
206    }
207
208    /// Perform in-place division (`self` / `y`) for a pre-shifted dividend and divisor.
209    ///
210    /// The dividend and divisor must be left-shifted such that the high bit of the divisor
211    /// is set, and `x_hi` holds the top bits of the dividend.
212    ///
213    /// The quotient is returned in `self` and the remainder in `y`, but these values require
214    /// additional correction. This is left to the caller for performance reasons.
215    #[inline(always)]
216    #[allow(clippy::cast_possible_truncation)]
217    pub(crate) const fn div_rem_shifted(&mut self, mut x_hi: Limb, y: &mut Self, ywords: u32) {
218        let x = self;
219
220        // Calculate a reciprocal from the highest word of the divisor
221        let reciprocal = Reciprocal::new(
222            y.limbs[y.nlimbs() - 1]
223                .to_nz()
224                .expect_copied("zero divisor"),
225        );
226        debug_assert!(reciprocal.shift() == 0);
227
228        // Perform the core division algorithm
229        x_hi = Self::div_rem_large_shifted(x, x_hi, y, ywords, reciprocal, Choice::FALSE);
230
231        // Calculate quotient and remainder for the case where the divisor is a single word.
232        let limb_div = Choice::from_u32_eq(1, ywords);
233        // Note that `div2by1()` will panic if `x_hi >= reciprocal.divisor_normalized`,
234        // but this can only be the case if `limb_div` is falsy, in which case we discard
235        // the result anyway, so we conditionally set `x_hi` to zero for this branch.
236        let x_hi_adjusted = Limb::select(Limb::ZERO, x_hi, limb_div);
237        let (quo2, rem2) = div2by1(x_hi_adjusted.0, x.limbs[0].0, &reciprocal);
238
239        // Adjust the quotient for single limb division
240        x.limbs[0] = Limb::select(x.limbs[0], Limb(quo2), limb_div);
241        // Copy out the low limb of the remainder
242        y.limbs[0] = Limb::select(x.limbs[0], Limb(rem2), limb_div);
243
244        // Adjust the remainder, copying `x_hi` to the appropriate position and clearing
245        // any extra limbs.
246        // Note: branching only based on the size of the operands, which is not secret.
247        let min = if x.nlimbs() < y.nlimbs() {
248            x.nlimbs()
249        } else {
250            y.nlimbs()
251        };
252        let hi_pos = u32_min(x.nlimbs() as u32, ywords - 1);
253        let mut i = 1;
254        while i < min {
255            y.limbs[i] = Limb::select(
256                Limb::ZERO,
257                x.limbs[i],
258                Choice::from_u32_lt(i as u32, ywords),
259            );
260            y.limbs[i] = Limb::select(y.limbs[i], x_hi, Choice::from_u32_eq(i as u32, hi_pos));
261            i += 1;
262        }
263        while i < y.nlimbs() {
264            y.limbs[i] = Limb::select(Limb::ZERO, x_hi, Choice::from_u32_eq(i as u32, hi_pos));
265            i += 1;
266        }
267    }
268
269    /// Computes `self` / `y` for a "large" divisor (>1 limbs), returning the quotient and
270    /// the remainder in `self`.
271    ///
272    /// While the divisor may only be a single limb, additional corrections to the result are
273    /// required in this case.
274    ///
275    /// The dividend and divisor must be left-shifted such that the high bit of the divisor
276    /// is set, and `x_hi` holds the top bits of the dividend.
277    #[inline(always)]
278    #[allow(clippy::cast_possible_truncation)]
279    pub(crate) const fn div_rem_large_shifted(
280        &mut self,
281        mut x_hi: Limb,
282        y: &Self,
283        ywords: u32,
284        reciprocal: Reciprocal,
285        vartime: Choice,
286    ) -> Limb {
287        let x = self;
288        let xsize = x.nlimbs();
289        let ysize = y.nlimbs();
290
291        let mut xi = xsize - 1;
292        let mut x_xi = x.limbs[xi];
293        let mut i;
294        let mut carry;
295
296        while xi > 0 {
297            // Divide high dividend words by the high divisor word to estimate the quotient word
298            let mut quo = div3by2(
299                x_hi.0,
300                x_xi.0,
301                x.limbs[xi - 1].0,
302                &reciprocal,
303                y.limbs[ysize - 2].0,
304            );
305
306            // This loop is a no-op once xi is smaller than the number of words in the divisor
307            let done = Choice::from_u32_lt(xi as u32, ywords - 1);
308            if vartime.and(done).to_bool_vartime() {
309                break;
310            }
311            quo = word::select(quo, 0, done);
312
313            // Subtract q*divisor from the dividend
314            let borrow = {
315                carry = Limb::ZERO;
316                let mut borrow = Limb::ZERO;
317                let mut tmp;
318                i = (xi + 1).saturating_sub(ysize);
319                while i <= xi {
320                    (tmp, carry) =
321                        y.limbs[ysize + i - xi - 1].carrying_mul_add(Limb(quo), carry, Limb::ZERO);
322                    (x.limbs[i], borrow) = x.limbs[i].borrowing_sub(tmp, borrow);
323                    i += 1;
324                }
325                (_, borrow) = x_hi.borrowing_sub(carry, borrow);
326                borrow
327            };
328
329            // If the subtraction borrowed, then decrement quo and add back the divisor
330            // The probability of this being needed is very low, about 2/(Limb::MAX+1)
331            quo = {
332                let ct_borrow = word::choice_from_mask(borrow.0);
333                carry = Limb::ZERO;
334                i = (xi + 1).saturating_sub(ysize);
335                while i <= xi {
336                    (x.limbs[i], carry) = x.limbs[i].carrying_add(
337                        Limb::select(Limb::ZERO, y.limbs[ysize + i - xi - 1], ct_borrow),
338                        carry,
339                    );
340                    i += 1;
341                }
342                word::select(quo, quo.saturating_sub(1), ct_borrow)
343            };
344
345            // Store the quotient within dividend and set x_hi to the current highest word
346            x_hi = Limb::select(x.limbs[xi], x_hi, done);
347            x.limbs[xi] = Limb::select(Limb(quo), x.limbs[xi], done);
348            x_xi = Limb::select(x.limbs[xi - 1], x_xi, done);
349            xi -= 1;
350        }
351
352        x_hi
353    }
354
355    /// Perform in-place variable-time division for a "large" divisor (>1 limbs). The
356    /// quotient is returned in `self` and the remainder in `rhs`.
357    #[inline(always)]
358    #[allow(clippy::cast_possible_truncation)]
359    pub(crate) const fn div_rem_large_vartime(&mut self, rhs: &mut Self) {
360        let (x, y) = (self, rhs);
361        let ysize = y.nlimbs();
362        debug_assert!(ysize > 1);
363        let lshift = y.limbs[ysize - 1].leading_zeros();
364
365        // Shift divisor such that it has no leading zeros
366        // This means that div2by1 requires no extra shifts, and ensures that the high word >= b/2
367        y.shl_assign_limb_vartime(lshift);
368
369        // Shift the dividend to match
370        let mut x_hi = x.shl_assign_limb_vartime(lshift);
371
372        // Calculate a reciprocal from the highest word of the divisor
373        let reciprocal = Reciprocal::new(y.limbs[ysize - 1].to_nz().expect_copied("zero divisor"));
374
375        // Perform the core division algorithm
376        x_hi = Self::div_rem_large_shifted(x, x_hi, y, ysize as u32, reciprocal, Choice::TRUE);
377
378        // Copy the remainder to divisor
379        y.leading_mut(ysize - 1).copy_from(x.leading(ysize - 1));
380        y.limbs[ysize - 1] = x_hi;
381
382        // Unshift the remainder from the earlier adjustment
383        y.shr_assign_limb_vartime(lshift);
384    }
385
386    /// Perform in-place division (`x` / `y`) for a pre-shifted dividend and divisor,
387    /// tracking only the remainder.
388    ///
389    /// The dividend and divisor must be left-shifted such that the high bit of the divisor
390    /// is set, and `x_hi` holds the top bits of the dividend.
391    ///
392    /// The shifted remainder is returned in `y`, and must be unshifted by the caller.
393    /// `x` is left in an indeterminate state.
394    #[inline(always)]
395    #[allow(clippy::cast_possible_truncation)]
396    const fn rem_wide_shifted(
397        x: (&mut Self, &mut Self),
398        mut x_hi: Limb,
399        y: &mut Self,
400        ywords: u32,
401    ) {
402        let (x_lo, x) = x;
403        let ysize = y.nlimbs();
404
405        // Calculate a reciprocal from the highest word of the divisor
406        let reciprocal = Reciprocal::new(y.limbs[ysize - 1].to_nz().expect_copied("zero divisor"));
407        debug_assert!(reciprocal.shift() == 0);
408
409        // Perform the core division algorithm
410        x_hi = Self::rem_wide_large_shifted((x_lo, x), x_hi, y, ywords, reciprocal, Choice::FALSE);
411
412        // Calculate remainder for the case where the divisor is a single word.
413        let limb_div = Choice::from_u32_eq(1, ywords);
414        // Note that `div2by1()` will panic if `x_hi >= reciprocal.divisor_normalized`,
415        // but this can only be the case if `limb_div` is falsy, in which case we discard
416        // the result anyway, so we conditionally set `x_hi` to zero for this branch.
417        let x_hi_adjusted = Limb::select(Limb::ZERO, x_hi, limb_div);
418        let (_, rem2) = div2by1(x_hi_adjusted.0, x.limbs[0].0, &reciprocal);
419
420        // Copy out the low limb of the remainder
421        y.limbs[0] = Limb::select(x.limbs[0], Limb(rem2), limb_div);
422
423        // Copy the remainder to divisor
424        let mut i = 1;
425        while i < ysize {
426            y.limbs[i] = Limb::select(
427                Limb::ZERO,
428                x.limbs[i],
429                Choice::from_u32_lt(i as u32, ywords),
430            );
431            y.limbs[i] = Limb::select(y.limbs[i], x_hi, Choice::from_u32_eq(i as u32, ywords - 1));
432            i += 1;
433        }
434    }
435
436    /// Computes `x % y` for a "large" divisor (>1 limbs), returning the remainder in `x.1`.
437    ///
438    /// While the divisor may only be a single limb, additional corrections to the result are
439    /// required in this case.
440    ///
441    /// The dividend and divisor must be left-shifted such that the high bit of the divisor
442    /// is set, and `x_hi` holds the top bits of the dividend.
443    #[inline(always)]
444    #[allow(clippy::cast_possible_truncation)]
445    const fn rem_wide_large_shifted(
446        x: (&Self, &mut Self),
447        mut x_hi: Limb,
448        y: &Self,
449        ywords: u32,
450        reciprocal: Reciprocal,
451        vartime: Choice,
452    ) -> Limb {
453        assert!(
454            y.nlimbs() <= x.1.nlimbs(),
455            "invalid input sizes for rem_wide_large_shifted"
456        );
457
458        let (x_lo, x) = x;
459        let xsize = x.nlimbs();
460        let ysize = y.nlimbs();
461        let mut extra_limbs = x_lo.nlimbs();
462
463        let mut xi = xsize - 1;
464        let mut x_xi = x.limbs[xi];
465        let mut i;
466        let mut carry;
467
468        // We proceed similarly to `div_rem_large_shifted()` applied to the high half of
469        // the dividend, fetching the limbs from the lower part as we go.
470
471        while xi > 0 {
472            // Divide high dividend words by the high divisor word to estimate the quotient word
473            let mut quo = div3by2(
474                x_hi.0,
475                x_xi.0,
476                x.limbs[xi - 1].0,
477                &reciprocal,
478                y.limbs[ysize - 2].0,
479            );
480
481            // This loop is a no-op once xi is smaller than the number of words in the divisor
482            let done = Choice::from_u32_lt(xi as u32, ywords - 1);
483            if vartime.and(done).to_bool_vartime() {
484                break;
485            }
486            quo = word::select(quo, 0, done);
487
488            // Subtract q*divisor from the dividend
489            let borrow = {
490                carry = Limb::ZERO;
491                let mut borrow = Limb::ZERO;
492                let mut tmp;
493                i = (xi + 1).saturating_sub(ysize);
494                while i <= xi {
495                    (tmp, carry) =
496                        y.limbs[ysize + i - xi - 1].carrying_mul_add(Limb(quo), carry, Limb::ZERO);
497                    (x.limbs[i], borrow) = x.limbs[i].borrowing_sub(tmp, borrow);
498                    i += 1;
499                }
500                (_, borrow) = x_hi.borrowing_sub(carry, borrow);
501                borrow
502            };
503
504            // If the subtraction borrowed, then add back the divisor
505            // The probability of this being needed is very low, about 2/(Limb::MAX+1)
506            {
507                let ct_borrow = word::choice_from_mask(borrow.0);
508                carry = Limb::ZERO;
509                i = (xi + 1).saturating_sub(ysize);
510                while i <= xi {
511                    (x.limbs[i], carry) = x.limbs[i].carrying_add(
512                        Limb::select(Limb::ZERO, y.limbs[ysize + i - xi - 1], ct_borrow),
513                        carry,
514                    );
515                    i += 1;
516                }
517            }
518
519            // If we have lower limbs remaining, shift the dividend words one word left
520            if extra_limbs > 0 {
521                x_hi = x.limbs[xi];
522                x_xi = x.limbs[xi - 1];
523                extra_limbs -= 1;
524                i = xi;
525                while i > 0 {
526                    x.limbs[i] = x.limbs[i - 1];
527                    i -= 1;
528                }
529                x.limbs[0] = x_lo.limbs[extra_limbs];
530            } else {
531                x_hi = Limb::select(x.limbs[xi], x_hi, done);
532                x_xi = Limb::select(x.limbs[xi - 1], x_xi, done);
533                xi -= 1;
534            }
535        }
536
537        x_hi
538    }
539
540    /// Divides `self` by the divisor encoded in the `reciprocal`, setting `self`
541    /// to the quotient and returning the remainder.
542    #[inline(always)]
543    pub(crate) const fn div_rem_limb(&mut self, rhs: NonZero<Limb>) -> Limb {
544        self.div_rem_limb_with_reciprocal(&Reciprocal::new(rhs))
545    }
546
547    /// Divides `self` by the divisor encoded in the `reciprocal`, setting `self`
548    /// to the quotient and returning the remainder.
549    #[inline(always)]
550    pub(crate) const fn div_rem_limb_with_reciprocal(&mut self, reciprocal: &Reciprocal) -> Limb {
551        let hi = self.shl_assign_limb(reciprocal.shift());
552        self.div_rem_limb_with_reciprocal_shifted(hi, reciprocal)
553    }
554
555    /// Divides `self` by the divisor encoded in the `reciprocal`, setting `self`
556    /// to the quotient and returning the remainder.
557    #[inline(always)]
558    pub(crate) const fn div_rem_limb_with_reciprocal_shifted(
559        &mut self,
560        mut hi: Limb,
561        reciprocal: &Reciprocal,
562    ) -> Limb {
563        let mut j = self.limbs.len();
564        while j > 0 {
565            j -= 1;
566            (self.limbs[j].0, hi.0) = div2by1(hi.0, self.limbs[j].0, reciprocal);
567        }
568        hi.shr(reciprocal.shift())
569    }
570
571    /// Divides `self` by the divisor encoded in the `reciprocal`, returning the remainder.
572    #[inline(always)]
573    pub(crate) const fn rem_limb(&self, rhs: NonZero<Limb>) -> Limb {
574        self.rem_limb_with_reciprocal(&Reciprocal::new(rhs), Limb::ZERO)
575    }
576
577    /// Divides `self` by the divisor encoded in the `reciprocal`, and returns the remainder.
578    pub(crate) const fn rem_limb_with_reciprocal(
579        &self,
580        reciprocal: &Reciprocal,
581        carry: Limb,
582    ) -> Limb {
583        let nlimbs = self.nlimbs();
584        if nlimbs == 0 {
585            return carry;
586        }
587        let lshift = reciprocal.shift();
588        let nz = Choice::from_u32_nz(lshift);
589        let rshift = nz.select_u32(0, Limb::BITS - lshift);
590        let mut hi = (carry.0 << lshift) | word::select(0, self.limbs[nlimbs - 1].0 >> rshift, nz);
591        let mut lo;
592        let mut j = nlimbs;
593        while j > 1 {
594            j -= 1;
595            lo = self.limbs[j].0 << lshift;
596            lo |= word::select(0, self.limbs[j - 1].0 >> rshift, nz);
597            (_, hi) = div2by1(hi, lo, reciprocal);
598        }
599        (_, hi) = div2by1(hi, self.limbs[0].0 << lshift, reciprocal);
600        Limb(hi >> lshift)
601    }
602}