Skip to main content

crypto_bigint/int/
div.rs

1//! [`Int`] division operations.
2
3use crate::{CheckedDiv, Choice, CtOption, DivVartime, Int, NonZero, Uint, Wrapping};
4use core::ops::{Div, DivAssign, Rem, RemAssign};
5
6/// Checked division operations.
7impl<const LIMBS: usize> Int<LIMBS> {
8    #[inline]
9    /// Base `div_rem` operation on dividing [`Int`]s.
10    ///
11    /// Computes the quotient and remainder of `self / rhs`.
12    /// Furthermore, returns the signs of `self` and `rhs`.
13    const fn div_rem_base<const RHS_LIMBS: usize>(
14        &self,
15        rhs: &NonZero<Int<RHS_LIMBS>>,
16    ) -> (Uint<LIMBS>, Uint<RHS_LIMBS>, Choice, Choice) {
17        // Step 1: split operands into signs and magnitudes.
18        let (lhs_mag, lhs_sgn) = self.abs_sign();
19        let (rhs_mag, rhs_sgn) = rhs.abs_sign();
20
21        // Step 2. Divide magnitudes
22        // safe to unwrap since rhs is NonZero.
23        let (quotient, remainder) = lhs_mag.div_rem(&rhs_mag);
24
25        (quotient, remainder, lhs_sgn, rhs_sgn)
26    }
27
28    /// Compute the quotient and remainder of `self / rhs`.
29    ///
30    /// Returns `none` for the quotient when [`Int::MIN`] / [`Int::MINUS_ONE`]; that quotient cannot
31    /// be captured in an [`Int`].
32    ///
33    /// Example:
34    /// ```
35    /// use crypto_bigint::{I128, NonZero};
36    /// let (quotient, remainder) = I128::from(8).checked_div_rem(&I128::from(3).to_nz().unwrap());
37    /// assert_eq!(quotient.unwrap(), I128::from(2));
38    /// assert_eq!(remainder, I128::from(2));
39    ///
40    /// let (quotient, remainder) = I128::from(-8).checked_div_rem(&I128::from(3).to_nz().unwrap());
41    /// assert_eq!(quotient.unwrap(), I128::from(-2));
42    /// assert_eq!(remainder, I128::from(-2));
43    ///
44    /// let (quotient, remainder) = I128::from(8).checked_div_rem(&I128::from(-3).to_nz().unwrap());
45    /// assert_eq!(quotient.unwrap(), I128::from(-2));
46    /// assert_eq!(remainder, I128::from(2));
47    ///
48    /// let (quotient, remainder) = I128::from(-8).checked_div_rem(&I128::from(-3).to_nz().unwrap());
49    /// assert_eq!(quotient.unwrap(), I128::from(2));
50    /// assert_eq!(remainder, I128::from(-2));
51    /// ```
52    #[must_use]
53    pub const fn checked_div_rem<const RHS_LIMBS: usize>(
54        &self,
55        rhs: &NonZero<Int<RHS_LIMBS>>,
56    ) -> (CtOption<Self>, Int<RHS_LIMBS>) {
57        let (quotient, remainder, lhs_sgn, rhs_sgn) = self.div_rem_base(rhs);
58        let opposing_signs = lhs_sgn.ne(rhs_sgn);
59        (
60            Self::new_from_abs_sign(quotient, opposing_signs),
61            remainder.as_int().wrapping_neg_if(lhs_sgn), // as_int mapping is safe; remainder < 2^{k-1} by construction.
62        )
63    }
64
65    /// Perform checked division, returning a [`CtOption`] which `is_some` if
66    /// - the `rhs != 0`, and
67    /// - `self != MIN` or `rhs != MINUS_ONE`.
68    ///
69    /// Note: this operation rounds towards zero, truncating any fractional part of the exact result.
70    #[must_use]
71    pub fn checked_div<const RHS_LIMBS: usize>(&self, rhs: &Int<RHS_LIMBS>) -> CtOption<Self> {
72        NonZero::new(*rhs).and_then(|rhs| self.checked_div_rem(&rhs).0)
73    }
74
75    /// Computes `self` % `rhs`, returns the remainder.
76    #[must_use]
77    pub const fn rem<const RHS_LIMBS: usize>(
78        &self,
79        rhs: &NonZero<Int<RHS_LIMBS>>,
80    ) -> Int<RHS_LIMBS> {
81        self.checked_div_rem(rhs).1
82    }
83}
84
85/// Vartime checked division operations.
86impl<const LIMBS: usize> Int<LIMBS> {
87    #[inline]
88    /// Variable time equivalent of [`Self::div_rem_base`]
89    ///
90    /// This is variable only with respect to `rhs`.
91    ///
92    /// When used with a fixed `rhs`, this function is constant-time with respect
93    /// to `self`.
94    const fn div_rem_base_vartime<const RHS_LIMBS: usize>(
95        &self,
96        rhs: &NonZero<Int<RHS_LIMBS>>,
97    ) -> (Uint<LIMBS>, Uint<RHS_LIMBS>, Choice, Choice) {
98        // Step 1: split operands into signs and magnitudes.
99        let (lhs_mag, lhs_sgn) = self.abs_sign();
100        let (rhs_mag, rhs_sgn) = rhs.abs_sign();
101
102        // Step 2. Divide magnitudes
103        // safe to unwrap since rhs is NonZero.
104        let (quotient, remainder) = lhs_mag.div_rem_vartime(&rhs_mag);
105
106        (quotient, remainder, lhs_sgn, rhs_sgn)
107    }
108
109    /// Variable time equivalent of [`Self::checked_div_rem`]
110    ///
111    /// This is variable only with respect to `rhs`.
112    ///
113    /// When used with a fixed `rhs`, this function is constant-time with respect
114    /// to `self`.
115    #[must_use]
116    pub const fn checked_div_rem_vartime<const RHS_LIMBS: usize>(
117        &self,
118        rhs: &NonZero<Int<RHS_LIMBS>>,
119    ) -> (CtOption<Self>, Int<RHS_LIMBS>) {
120        let (quotient, remainder, lhs_sgn, rhs_sgn) = self.div_rem_base_vartime(rhs);
121        let opposing_signs = lhs_sgn.ne(rhs_sgn);
122        (
123            Self::new_from_abs_sign(quotient, opposing_signs),
124            remainder.as_int().wrapping_neg_if(lhs_sgn), // as_int mapping is safe; remainder < 2^{k-1} by construction.
125        )
126    }
127
128    /// Variable time equivalent of [`Self::checked_div`]
129    ///
130    /// This is variable only with respect to `rhs`.
131    ///
132    /// When used with a fixed `rhs`, this function is constant-time with respect
133    /// to `self`.
134    #[must_use]
135    pub fn checked_div_vartime<const RHS_LIMBS: usize>(
136        &self,
137        rhs: &Int<RHS_LIMBS>,
138    ) -> CtOption<Self> {
139        NonZero::new(*rhs).and_then(|rhs| self.checked_div_rem_vartime(&rhs).0)
140    }
141
142    /// Variable time equivalent of [`Self::rem`]
143    ///
144    /// This is variable only with respect to `rhs`.
145    ///
146    /// When used with a fixed `rhs`, this function is constant-time with respect
147    /// to `self`.
148    #[must_use]
149    pub const fn rem_vartime<const RHS_LIMBS: usize>(
150        &self,
151        rhs: &NonZero<Int<RHS_LIMBS>>,
152    ) -> Int<RHS_LIMBS> {
153        self.checked_div_rem_vartime(rhs).1
154    }
155}
156
157/// Vartime checked div-floor operations.
158impl<const LIMBS: usize> Int<LIMBS> {
159    /// Variable time equivalent of [`Self::checked_div_rem_floor`]
160    ///
161    /// This is variable only with respect to `rhs`.
162    ///
163    /// When used with a fixed `rhs`, this function is constant-time with respect
164    /// to `self`.
165    #[must_use]
166    pub const fn checked_div_rem_floor_vartime<const RHS_LIMBS: usize>(
167        &self,
168        rhs: &NonZero<Int<RHS_LIMBS>>,
169    ) -> (CtOption<Self>, Int<RHS_LIMBS>) {
170        let (lhs_mag, lhs_sgn) = self.abs_sign();
171        let (rhs_mag, rhs_sgn) = rhs.abs_sign();
172        let (quotient, remainder) = lhs_mag.div_rem_vartime(&rhs_mag);
173
174        // Modify quotient and remainder when lhs and rhs have opposing signs and the remainder is
175        // non-zero.
176        let opposing_signs = lhs_sgn.xor(rhs_sgn);
177        let modify = remainder.is_nonzero().and(opposing_signs);
178
179        // Increase the quotient by one.
180        let quotient_plus_one = quotient.wrapping_add(&Uint::ONE); // cannot wrap.
181        let quotient = Uint::select(&quotient, &quotient_plus_one, modify);
182
183        // Invert the remainder.
184        let inv_remainder = rhs_mag.0.wrapping_sub(&remainder);
185        let remainder = Uint::select(&remainder, &inv_remainder, modify);
186
187        // Negate output when lhs and rhs have opposing signs.
188        let quotient = Int::new_from_abs_sign(quotient, opposing_signs);
189        let remainder = remainder.as_int().wrapping_neg_if(opposing_signs); // rem always small enough for safe as_int conversion
190
191        (quotient, remainder)
192    }
193
194    /// Variable time equivalent of [`Self::checked_div_floor`]
195    ///
196    /// This is variable only with respect to `rhs`.
197    ///
198    /// When used with a fixed `rhs`, this function is constant-time with respect
199    /// to `self`.
200    #[must_use]
201    pub fn checked_div_floor_vartime<const RHS_LIMBS: usize>(
202        &self,
203        rhs: &Int<RHS_LIMBS>,
204    ) -> CtOption<Self> {
205        NonZero::new(*rhs).and_then(|rhs| self.checked_div_rem_floor_vartime(&rhs).0)
206    }
207}
208
209/// Checked div-floor operations.
210impl<const LIMBS: usize> Int<LIMBS> {
211    /// Perform checked floored division, returning a [`CtOption`] which `is_some` only if
212    /// - the `rhs != 0`, and
213    /// - `self != MIN` or `rhs != MINUS_ONE`.
214    ///
215    /// Note: this operation rounds down.
216    ///
217    /// Example:
218    /// ```
219    /// use crypto_bigint::I128;
220    /// assert_eq!(
221    ///     I128::from(8).checked_div_floor(&I128::from(3)).unwrap(),
222    ///     I128::from(2)
223    /// );
224    /// assert_eq!(
225    ///     I128::from(-8).checked_div_floor(&I128::from(3)).unwrap(),
226    ///     I128::from(-3)
227    /// );
228    /// assert_eq!(
229    ///     I128::from(8).checked_div_floor(&I128::from(-3)).unwrap(),
230    ///     I128::from(-3)
231    /// );
232    /// assert_eq!(
233    ///     I128::from(-8).checked_div_floor(&I128::from(-3)).unwrap(),
234    ///     I128::from(2)
235    /// )
236    /// ```
237    #[must_use]
238    pub fn checked_div_floor<const RHS_LIMBS: usize>(
239        &self,
240        rhs: &Int<RHS_LIMBS>,
241    ) -> CtOption<Self> {
242        NonZero::new(*rhs).and_then(|rhs| self.checked_div_rem_floor(&rhs).0)
243    }
244
245    /// Perform checked division and mod, returning the quotient and remainder.
246    ///
247    /// The quotient is a [`CtOption`] which `is_some` only if
248    /// - the `rhs != 0`, and
249    /// - `self != MIN` or `rhs != MINUS_ONE`.
250    ///
251    /// Note: this operation rounds down.
252    ///
253    /// Example:
254    /// ```
255    /// use crypto_bigint::I128;
256    ///
257    /// let three = I128::from(3).to_nz().unwrap();
258    /// let (quotient, remainder) = I128::from(8).checked_div_rem_floor(&three);
259    /// assert_eq!(quotient.unwrap(), I128::from(2));
260    /// assert_eq!(remainder, I128::from(2));
261    ///
262    /// let (quotient, remainder) = I128::from(-8).checked_div_rem_floor(&three);
263    /// assert_eq!(quotient.unwrap(), I128::from(-3));
264    /// assert_eq!(remainder, I128::from(-1));
265    ///
266    /// let minus_three = I128::from(-3).to_nz().unwrap();
267    /// let (quotient, remainder) = I128::from(8).checked_div_rem_floor(&minus_three);
268    /// assert_eq!(quotient.unwrap(), I128::from(-3));
269    /// assert_eq!(remainder, I128::from(-1));
270    ///
271    /// let (quotient, remainder) = I128::from(-8).checked_div_rem_floor(&minus_three);
272    /// assert_eq!(quotient.unwrap(), I128::from(2));
273    /// assert_eq!(remainder, I128::from(2));
274    /// ```
275    #[must_use]
276    pub const fn checked_div_rem_floor<const RHS_LIMBS: usize>(
277        &self,
278        rhs: &NonZero<Int<RHS_LIMBS>>,
279    ) -> (CtOption<Self>, Int<RHS_LIMBS>) {
280        let (lhs_mag, lhs_sgn) = self.abs_sign();
281        let (rhs_mag, rhs_sgn) = rhs.abs_sign();
282        let (quotient, remainder) = lhs_mag.div_rem(&rhs_mag);
283
284        // Modify quotient and remainder when lhs and rhs have opposing signs and the remainder is
285        // non-zero.
286        let opposing_signs = lhs_sgn.xor(rhs_sgn);
287        let modify = remainder.is_nonzero().and(opposing_signs);
288
289        // Increase the quotient by one.
290        let quotient_plus_one = quotient.wrapping_add(&Uint::ONE); // cannot wrap.
291        let quotient = Uint::select(&quotient, &quotient_plus_one, modify);
292
293        // Invert the remainder.
294        let inv_remainder = rhs_mag.0.wrapping_sub(&remainder);
295        let remainder = Uint::select(&remainder, &inv_remainder, modify);
296
297        // Negate output when lhs and rhs have opposing signs.
298        let quotient = Int::new_from_abs_sign(quotient, opposing_signs);
299        let remainder = remainder.as_int().wrapping_neg_if(opposing_signs); // rem always small enough for safe as_int conversion
300
301        (quotient, remainder)
302    }
303}
304
305impl<const LIMBS: usize, const RHS_LIMBS: usize> CheckedDiv<Int<RHS_LIMBS>> for Int<LIMBS> {
306    fn checked_div(&self, rhs: &Int<RHS_LIMBS>) -> CtOption<Self> {
307        self.checked_div(rhs)
308    }
309}
310
311impl<const LIMBS: usize, const RHS_LIMBS: usize> Div<&NonZero<Int<RHS_LIMBS>>> for &Int<LIMBS> {
312    type Output = CtOption<Int<LIMBS>>;
313
314    fn div(self, rhs: &NonZero<Int<RHS_LIMBS>>) -> Self::Output {
315        *self / *rhs
316    }
317}
318
319impl<const LIMBS: usize, const RHS_LIMBS: usize> Div<&NonZero<Int<RHS_LIMBS>>> for Int<LIMBS> {
320    type Output = CtOption<Int<LIMBS>>;
321
322    fn div(self, rhs: &NonZero<Int<RHS_LIMBS>>) -> Self::Output {
323        self / *rhs
324    }
325}
326
327impl<const LIMBS: usize, const RHS_LIMBS: usize> Div<NonZero<Int<RHS_LIMBS>>> for &Int<LIMBS> {
328    type Output = CtOption<Int<LIMBS>>;
329
330    fn div(self, rhs: NonZero<Int<RHS_LIMBS>>) -> Self::Output {
331        *self / rhs
332    }
333}
334
335impl<const LIMBS: usize, const RHS_LIMBS: usize> Div<NonZero<Int<RHS_LIMBS>>> for Int<LIMBS> {
336    type Output = CtOption<Int<LIMBS>>;
337
338    fn div(self, rhs: NonZero<Int<RHS_LIMBS>>) -> Self::Output {
339        self.checked_div(&rhs)
340    }
341}
342
343impl<const LIMBS: usize> DivAssign<&NonZero<Int<LIMBS>>> for Int<LIMBS> {
344    fn div_assign(&mut self, rhs: &NonZero<Int<LIMBS>>) {
345        *self /= *rhs;
346    }
347}
348
349impl<const LIMBS: usize> DivAssign<NonZero<Int<LIMBS>>> for Int<LIMBS> {
350    fn div_assign(&mut self, rhs: NonZero<Int<LIMBS>>) {
351        *self = (*self / rhs).expect("cannot represent positive equivalent of Int::MIN as int");
352    }
353}
354
355impl<const LIMBS: usize> DivVartime for Int<LIMBS> {
356    fn div_vartime(&self, rhs: &NonZero<Int<LIMBS>>) -> Self {
357        let (q, _r, lhs_sign, rhs_sign) = self.div_rem_base_vartime(rhs);
358        let opposing_signs = lhs_sign.xor(rhs_sign);
359        let q = Int::new_from_abs_sign(q, opposing_signs);
360        q.expect("int divided by int fits in uint by construction")
361    }
362}
363
364impl<const LIMBS: usize, const RHS_LIMBS: usize> Div<NonZero<Int<RHS_LIMBS>>>
365    for Wrapping<Int<LIMBS>>
366{
367    type Output = Wrapping<Int<LIMBS>>;
368
369    fn div(self, rhs: NonZero<Int<RHS_LIMBS>>) -> Self::Output {
370        Wrapping((self.0 / rhs).expect("cannot represent positive equivalent of Int::MIN as int"))
371    }
372}
373
374impl<const LIMBS: usize, const RHS_LIMBS: usize> Div<NonZero<Int<RHS_LIMBS>>>
375    for &Wrapping<Int<LIMBS>>
376{
377    type Output = Wrapping<Int<LIMBS>>;
378
379    fn div(self, rhs: NonZero<Int<RHS_LIMBS>>) -> Self::Output {
380        *self / rhs
381    }
382}
383
384impl<const LIMBS: usize, const RHS_LIMBS: usize> Div<&NonZero<Int<RHS_LIMBS>>>
385    for &Wrapping<Int<LIMBS>>
386{
387    type Output = Wrapping<Int<LIMBS>>;
388
389    fn div(self, rhs: &NonZero<Int<RHS_LIMBS>>) -> Self::Output {
390        *self / *rhs
391    }
392}
393
394impl<const LIMBS: usize, const RHS_LIMBS: usize> Div<&NonZero<Int<RHS_LIMBS>>>
395    for Wrapping<Int<LIMBS>>
396{
397    type Output = Wrapping<Int<LIMBS>>;
398
399    fn div(self, rhs: &NonZero<Int<RHS_LIMBS>>) -> Self::Output {
400        self / *rhs
401    }
402}
403
404impl<const LIMBS: usize> DivAssign<&NonZero<Int<LIMBS>>> for Wrapping<Int<LIMBS>> {
405    fn div_assign(&mut self, rhs: &NonZero<Int<LIMBS>>) {
406        *self = Wrapping(
407            (self.0 / rhs).expect("cannot represent positive equivalent of Int::MIN as int"),
408        );
409    }
410}
411
412impl<const LIMBS: usize> DivAssign<NonZero<Int<LIMBS>>> for Wrapping<Int<LIMBS>> {
413    fn div_assign(&mut self, rhs: NonZero<Int<LIMBS>>) {
414        *self /= &rhs;
415    }
416}
417
418impl<const LIMBS: usize, const RHS_LIMBS: usize> Rem<&NonZero<Int<RHS_LIMBS>>> for &Int<LIMBS> {
419    type Output = Int<RHS_LIMBS>;
420
421    fn rem(self, rhs: &NonZero<Int<RHS_LIMBS>>) -> Self::Output {
422        *self % *rhs
423    }
424}
425
426impl<const LIMBS: usize, const RHS_LIMBS: usize> Rem<&NonZero<Int<RHS_LIMBS>>> for Int<LIMBS> {
427    type Output = Int<RHS_LIMBS>;
428
429    fn rem(self, rhs: &NonZero<Int<RHS_LIMBS>>) -> Self::Output {
430        self % *rhs
431    }
432}
433
434impl<const LIMBS: usize, const RHS_LIMBS: usize> Rem<NonZero<Int<RHS_LIMBS>>> for &Int<LIMBS> {
435    type Output = Int<RHS_LIMBS>;
436
437    fn rem(self, rhs: NonZero<Int<RHS_LIMBS>>) -> Self::Output {
438        *self % rhs
439    }
440}
441
442impl<const LIMBS: usize, const RHS_LIMBS: usize> Rem<NonZero<Int<RHS_LIMBS>>> for Int<LIMBS> {
443    type Output = Int<RHS_LIMBS>;
444
445    fn rem(self, rhs: NonZero<Int<RHS_LIMBS>>) -> Self::Output {
446        Self::rem(&self, &rhs)
447    }
448}
449
450impl<const LIMBS: usize> RemAssign<&NonZero<Int<LIMBS>>> for Int<LIMBS> {
451    fn rem_assign(&mut self, rhs: &NonZero<Int<LIMBS>>) {
452        *self %= *rhs;
453    }
454}
455
456impl<const LIMBS: usize> RemAssign<NonZero<Int<LIMBS>>> for Int<LIMBS> {
457    fn rem_assign(&mut self, rhs: NonZero<Int<LIMBS>>) {
458        *self = *self % rhs;
459    }
460}
461
462impl<const LIMBS: usize, const RHS_LIMBS: usize> Rem<NonZero<Int<RHS_LIMBS>>>
463    for Wrapping<Int<LIMBS>>
464{
465    type Output = Wrapping<Int<RHS_LIMBS>>;
466
467    fn rem(self, rhs: NonZero<Int<RHS_LIMBS>>) -> Self::Output {
468        Wrapping(self.0 % rhs)
469    }
470}
471
472impl<const LIMBS: usize, const RHS_LIMBS: usize> Rem<NonZero<Int<RHS_LIMBS>>>
473    for &Wrapping<Int<LIMBS>>
474{
475    type Output = Wrapping<Int<RHS_LIMBS>>;
476
477    fn rem(self, rhs: NonZero<Int<RHS_LIMBS>>) -> Self::Output {
478        *self % rhs
479    }
480}
481
482impl<const LIMBS: usize, const RHS_LIMBS: usize> Rem<&NonZero<Int<RHS_LIMBS>>>
483    for &Wrapping<Int<LIMBS>>
484{
485    type Output = Wrapping<Int<RHS_LIMBS>>;
486
487    fn rem(self, rhs: &NonZero<Int<RHS_LIMBS>>) -> Self::Output {
488        *self % *rhs
489    }
490}
491
492impl<const LIMBS: usize, const RHS_LIMBS: usize> Rem<&NonZero<Int<RHS_LIMBS>>>
493    for Wrapping<Int<LIMBS>>
494{
495    type Output = Wrapping<Int<RHS_LIMBS>>;
496
497    fn rem(self, rhs: &NonZero<Int<RHS_LIMBS>>) -> Self::Output {
498        self % *rhs
499    }
500}
501
502impl<const LIMBS: usize> RemAssign<NonZero<Int<LIMBS>>> for Wrapping<Int<LIMBS>> {
503    fn rem_assign(&mut self, rhs: NonZero<Int<LIMBS>>) {
504        *self %= &rhs;
505    }
506}
507
508impl<const LIMBS: usize> RemAssign<&NonZero<Int<LIMBS>>> for Wrapping<Int<LIMBS>> {
509    fn rem_assign(&mut self, rhs: &NonZero<Int<LIMBS>>) {
510        *self = Wrapping(self.0 % rhs);
511    }
512}
513
514#[cfg(test)]
515mod tests {
516    use crate::{CtAssign, DivVartime, I128, Int, NonZero, One, Zero};
517
518    #[test]
519    #[allow(clippy::init_numbered_fields)]
520    fn test_checked_div() {
521        let min_plus_one = Int {
522            0: I128::MIN.0.wrapping_add(&I128::ONE.0),
523        };
524
525        // lhs = min
526
527        let result = I128::MIN.checked_div(&I128::MIN);
528        assert_eq!(result.unwrap(), I128::ONE);
529
530        let result = I128::MIN.checked_div(&I128::MINUS_ONE);
531        assert!(bool::from(result.is_none()));
532
533        let result = I128::MIN.checked_div(&I128::ZERO);
534        assert!(bool::from(result.is_none()));
535
536        let result = I128::MIN.checked_div(&I128::ONE);
537        assert_eq!(result.unwrap(), I128::MIN);
538
539        let result = I128::MIN.checked_div(&I128::MAX);
540        assert_eq!(result.unwrap(), I128::MINUS_ONE);
541
542        // lhs = -1
543
544        let result = I128::MINUS_ONE.checked_div(&I128::MIN);
545        assert_eq!(result.unwrap(), I128::ZERO);
546
547        let result = I128::MINUS_ONE.checked_div(&I128::MINUS_ONE);
548        assert_eq!(result.unwrap(), I128::ONE);
549
550        let result = I128::MINUS_ONE.checked_div(&I128::ZERO);
551        assert!(bool::from(result.is_none()));
552
553        let result = I128::MINUS_ONE.checked_div(&I128::ONE);
554        assert_eq!(result.unwrap(), I128::MINUS_ONE);
555
556        let result = I128::MINUS_ONE.checked_div(&I128::MAX);
557        assert_eq!(result.unwrap(), I128::ZERO);
558
559        // lhs = 0
560
561        let result = I128::ZERO.checked_div(&I128::MIN);
562        assert_eq!(result.unwrap(), I128::ZERO);
563
564        let result = I128::ZERO.checked_div(&I128::MINUS_ONE);
565        assert_eq!(result.unwrap(), I128::ZERO);
566
567        let result = I128::ZERO.checked_div(&I128::ZERO);
568        assert!(bool::from(result.is_none()));
569
570        let result = I128::ZERO.checked_div(&I128::ONE);
571        assert_eq!(result.unwrap(), I128::ZERO);
572
573        let result = I128::ZERO.checked_div(&I128::MAX);
574        assert_eq!(result.unwrap(), I128::ZERO);
575
576        // lhs = 1
577
578        let result = I128::ONE.checked_div(&I128::MIN);
579        assert_eq!(result.unwrap(), I128::ZERO);
580
581        let result = I128::ONE.checked_div(&I128::MINUS_ONE);
582        assert_eq!(result.unwrap(), I128::MINUS_ONE);
583
584        let result = I128::ONE.checked_div(&I128::ZERO);
585        assert!(bool::from(result.is_none()));
586
587        let result = I128::ONE.checked_div(&I128::ONE);
588        assert_eq!(result.unwrap(), I128::ONE);
589
590        let result = I128::ONE.checked_div(&I128::MAX);
591        assert_eq!(result.unwrap(), I128::ZERO);
592
593        // lhs = max
594
595        let result = I128::MAX.checked_div(&I128::MIN);
596        assert_eq!(result.unwrap(), I128::ZERO);
597
598        let result = I128::MAX.checked_div(&I128::MINUS_ONE);
599        assert_eq!(result.unwrap(), min_plus_one);
600
601        let result = I128::MAX.checked_div(&I128::ZERO);
602        assert!(bool::from(result.is_none()));
603
604        let result = I128::MAX.checked_div(&I128::ONE);
605        assert_eq!(result.unwrap(), I128::MAX);
606
607        let result = I128::MAX.checked_div(&I128::MAX);
608        assert_eq!(result.unwrap(), I128::ONE);
609    }
610
611    #[test]
612    fn test_checked_div_floor() {
613        assert_eq!(
614            I128::from(8).checked_div_floor(&I128::from(3)).unwrap(),
615            I128::from(2)
616        );
617        assert_eq!(
618            I128::from(-8).checked_div_floor(&I128::from(3)).unwrap(),
619            I128::from(-3)
620        );
621        assert_eq!(
622            I128::from(8).checked_div_floor(&I128::from(-3)).unwrap(),
623            I128::from(-3)
624        );
625        assert_eq!(
626            I128::from(-8).checked_div_floor(&I128::from(-3)).unwrap(),
627            I128::from(2)
628        );
629    }
630
631    #[test]
632    fn test_checked_div_mod_floor() {
633        let (quotient, remainder) =
634            I128::MIN.checked_div_rem_floor(&I128::MINUS_ONE.to_nz().unwrap());
635        assert!(!quotient.is_some().to_bool());
636        assert_eq!(remainder, I128::ZERO);
637    }
638
639    #[test]
640    fn div_vartime_through_trait() {
641        fn myfn<T: DivVartime + Zero + One + CtAssign>(x: T, y: T) -> T {
642            x.div_vartime(&NonZero::new(y).unwrap())
643        }
644        assert_eq!(myfn(I128::from(8), I128::from(3)), I128::from(2));
645        assert_eq!(myfn(I128::from(-8), I128::from(3)), I128::from(-2));
646        assert_eq!(myfn(I128::from(8), I128::from(-3)), I128::from(-2));
647        assert_eq!(myfn(I128::from(-8), I128::from(-3)), I128::from(2));
648        assert_eq!(myfn(I128::MAX, I128::from(1)), I128::MAX);
649        assert_eq!(myfn(I128::MAX, I128::MAX), I128::from(1));
650    }
651}