1use crate::{CheckedDiv, Choice, CtOption, DivVartime, Int, NonZero, Uint, Wrapping};
4use core::ops::{Div, DivAssign, Rem, RemAssign};
5
6impl<const LIMBS: usize> Int<LIMBS> {
8 #[inline]
9 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 let (lhs_mag, lhs_sgn) = self.abs_sign();
19 let (rhs_mag, rhs_sgn) = rhs.abs_sign();
20
21 let (quotient, remainder) = lhs_mag.div_rem(&rhs_mag);
24
25 (quotient, remainder, lhs_sgn, rhs_sgn)
26 }
27
28 #[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), )
63 }
64
65 #[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 #[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
85impl<const LIMBS: usize> Int<LIMBS> {
87 #[inline]
88 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 let (lhs_mag, lhs_sgn) = self.abs_sign();
100 let (rhs_mag, rhs_sgn) = rhs.abs_sign();
101
102 let (quotient, remainder) = lhs_mag.div_rem_vartime(&rhs_mag);
105
106 (quotient, remainder, lhs_sgn, rhs_sgn)
107 }
108
109 #[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), )
126 }
127
128 #[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 #[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
157impl<const LIMBS: usize> Int<LIMBS> {
159 #[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 let opposing_signs = lhs_sgn.xor(rhs_sgn);
177 let modify = remainder.is_nonzero().and(opposing_signs);
178
179 let quotient_plus_one = quotient.wrapping_add(&Uint::ONE); let quotient = Uint::select("ient, "ient_plus_one, modify);
182
183 let inv_remainder = rhs_mag.0.wrapping_sub(&remainder);
185 let remainder = Uint::select(&remainder, &inv_remainder, modify);
186
187 let quotient = Int::new_from_abs_sign(quotient, opposing_signs);
189 let remainder = remainder.as_int().wrapping_neg_if(opposing_signs); (quotient, remainder)
192 }
193
194 #[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
209impl<const LIMBS: usize> Int<LIMBS> {
211 #[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 #[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 let opposing_signs = lhs_sgn.xor(rhs_sgn);
287 let modify = remainder.is_nonzero().and(opposing_signs);
288
289 let quotient_plus_one = quotient.wrapping_add(&Uint::ONE); let quotient = Uint::select("ient, "ient_plus_one, modify);
292
293 let inv_remainder = rhs_mag.0.wrapping_sub(&remainder);
295 let remainder = Uint::select(&remainder, &inv_remainder, modify);
296
297 let quotient = Int::new_from_abs_sign(quotient, opposing_signs);
299 let remainder = remainder.as_int().wrapping_neg_if(opposing_signs); (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 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 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 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 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 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}