1use core::ops::{Div, DivAssign, Rem, RemAssign};
4
5use subtle::CtOption;
6
7use crate::{CheckedDiv, ConstChoice, ConstCtOption, Int, NonZero, Uint, Wrapping};
8
9impl<const LIMBS: usize> Int<LIMBS> {
11 #[inline]
12 const fn div_rem_base(
17 &self,
18 rhs: &NonZero<Self>,
19 ) -> (Uint<{ LIMBS }>, Uint<{ LIMBS }>, ConstChoice, ConstChoice) {
20 let (lhs_mag, lhs_sgn) = self.abs_sign();
22 let (rhs_mag, rhs_sgn) = rhs.abs_sign();
23
24 let (quotient, remainder) = lhs_mag.div_rem(&rhs_mag);
27
28 (quotient, remainder, lhs_sgn, rhs_sgn)
29 }
30
31 pub const fn checked_div_rem(&self, rhs: &NonZero<Self>) -> (ConstCtOption<Self>, Self) {
56 let (quotient, remainder, lhs_sgn, rhs_sgn) = self.div_rem_base(rhs);
57 let opposing_signs = lhs_sgn.ne(rhs_sgn);
58 (
59 Self::new_from_abs_sign(quotient, opposing_signs),
60 remainder.as_int().wrapping_neg_if(lhs_sgn), )
62 }
63
64 pub fn checked_div(&self, rhs: &Self) -> CtOption<Self> {
70 NonZero::new(*rhs).and_then(|rhs| self.checked_div_rem(&rhs).0.into())
71 }
72
73 pub const fn rem(&self, rhs: &NonZero<Self>) -> Self {
75 self.checked_div_rem(rhs).1
76 }
77}
78
79impl<const LIMBS: usize> Int<LIMBS> {
81 #[inline]
82 const fn div_rem_base_vartime<const RHS_LIMBS: usize>(
89 &self,
90 rhs: &NonZero<Int<RHS_LIMBS>>,
91 ) -> (Uint<LIMBS>, Uint<RHS_LIMBS>, ConstChoice, ConstChoice) {
92 let (lhs_mag, lhs_sgn) = self.abs_sign();
94 let (rhs_mag, rhs_sgn) = rhs.abs_sign();
95
96 let (quotient, remainder) = lhs_mag.div_rem_vartime(&rhs_mag);
99
100 (quotient, remainder, lhs_sgn, rhs_sgn)
101 }
102
103 pub const fn checked_div_rem_vartime<const RHS_LIMBS: usize>(
110 &self,
111 rhs: &NonZero<Int<RHS_LIMBS>>,
112 ) -> (ConstCtOption<Self>, Int<RHS_LIMBS>) {
113 let (quotient, remainder, lhs_sgn, rhs_sgn) = self.div_rem_base_vartime(rhs);
114 let opposing_signs = lhs_sgn.ne(rhs_sgn);
115 (
116 Self::new_from_abs_sign(quotient, opposing_signs),
117 remainder.as_int().wrapping_neg_if(lhs_sgn), )
119 }
120
121 pub fn checked_div_vartime<const RHS_LIMBS: usize>(
128 &self,
129 rhs: &Int<RHS_LIMBS>,
130 ) -> CtOption<Self> {
131 NonZero::new(*rhs).and_then(|rhs| self.checked_div_rem_vartime(&rhs).0.into())
132 }
133
134 pub const fn rem_vartime<const RHS_LIMBS: usize>(
141 &self,
142 rhs: &NonZero<Int<RHS_LIMBS>>,
143 ) -> Int<RHS_LIMBS> {
144 self.checked_div_rem_vartime(rhs).1
145 }
146}
147
148impl<const LIMBS: usize> Int<LIMBS> {
150 pub const fn checked_div_rem_floor_vartime<const RHS_LIMBS: usize>(
157 &self,
158 rhs: &NonZero<Int<RHS_LIMBS>>,
159 ) -> (ConstCtOption<Self>, Int<RHS_LIMBS>) {
160 let (lhs_mag, lhs_sgn) = self.abs_sign();
161 let (rhs_mag, rhs_sgn) = rhs.abs_sign();
162 let (quotient, remainder) = lhs_mag.div_rem_vartime(&rhs_mag);
163
164 let opposing_signs = lhs_sgn.xor(rhs_sgn);
167 let modify = remainder.is_nonzero().and(opposing_signs);
168
169 let quotient_plus_one = quotient.wrapping_add(&Uint::ONE); let quotient = Uint::select("ient, "ient_plus_one, modify);
172
173 let inv_remainder = rhs_mag.0.wrapping_sub(&remainder);
175 let remainder = Uint::select(&remainder, &inv_remainder, modify);
176
177 let quotient = Int::new_from_abs_sign(quotient, opposing_signs);
179 let remainder = remainder.as_int().wrapping_neg_if(opposing_signs); (quotient, remainder)
182 }
183
184 pub fn checked_div_floor_vartime<const RHS_LIMBS: usize>(
191 &self,
192 rhs: &Int<RHS_LIMBS>,
193 ) -> CtOption<Self> {
194 NonZero::new(*rhs).and_then(|rhs| self.checked_div_rem_floor_vartime(&rhs).0.into())
195 }
196}
197
198impl<const LIMBS: usize> Int<LIMBS> {
200 pub fn checked_div_floor(&self, rhs: &Self) -> CtOption<Self> {
227 NonZero::new(*rhs).and_then(|rhs| self.checked_div_rem_floor(&rhs).0.into())
228 }
229
230 pub const fn checked_div_rem_floor(&self, rhs: &NonZero<Self>) -> (ConstCtOption<Self>, Self) {
261 let (lhs_mag, lhs_sgn) = self.abs_sign();
262 let (rhs_mag, rhs_sgn) = rhs.abs_sign();
263 let (quotient, remainder) = lhs_mag.div_rem(&rhs_mag);
264
265 let opposing_signs = lhs_sgn.xor(rhs_sgn);
268 let modify = remainder.is_nonzero().and(opposing_signs);
269
270 let quotient_plus_one = quotient.wrapping_add(&Uint::ONE); let quotient = Uint::select("ient, "ient_plus_one, modify);
273
274 let inv_remainder = rhs_mag.0.wrapping_sub(&remainder);
276 let remainder = Uint::select(&remainder, &inv_remainder, modify);
277
278 let quotient = Int::new_from_abs_sign(quotient, opposing_signs);
280 let remainder = remainder.as_int().wrapping_neg_if(opposing_signs); (quotient, remainder)
283 }
284}
285
286impl<const LIMBS: usize> CheckedDiv for Int<LIMBS> {
287 fn checked_div(&self, rhs: &Int<LIMBS>) -> CtOption<Self> {
288 self.checked_div(rhs)
289 }
290}
291
292impl<const LIMBS: usize> Div<&NonZero<Int<LIMBS>>> for &Int<LIMBS> {
293 type Output = CtOption<Int<LIMBS>>;
294
295 fn div(self, rhs: &NonZero<Int<LIMBS>>) -> Self::Output {
296 *self / *rhs
297 }
298}
299
300impl<const LIMBS: usize> Div<&NonZero<Int<LIMBS>>> for Int<LIMBS> {
301 type Output = CtOption<Int<LIMBS>>;
302
303 fn div(self, rhs: &NonZero<Int<LIMBS>>) -> Self::Output {
304 self / *rhs
305 }
306}
307
308impl<const LIMBS: usize> Div<NonZero<Int<LIMBS>>> for &Int<LIMBS> {
309 type Output = CtOption<Int<LIMBS>>;
310
311 fn div(self, rhs: NonZero<Int<LIMBS>>) -> Self::Output {
312 *self / rhs
313 }
314}
315
316impl<const LIMBS: usize> Div<NonZero<Int<LIMBS>>> for Int<LIMBS> {
317 type Output = CtOption<Int<LIMBS>>;
318
319 fn div(self, rhs: NonZero<Int<LIMBS>>) -> Self::Output {
320 self.checked_div(&rhs)
321 }
322}
323
324impl<const LIMBS: usize> DivAssign<&NonZero<Int<LIMBS>>> for Int<LIMBS> {
325 fn div_assign(&mut self, rhs: &NonZero<Int<LIMBS>>) {
326 *self /= *rhs
327 }
328}
329
330impl<const LIMBS: usize> DivAssign<NonZero<Int<LIMBS>>> for Int<LIMBS> {
331 fn div_assign(&mut self, rhs: NonZero<Int<LIMBS>>) {
332 *self = (*self / rhs).expect("cannot represent positive equivalent of Int::MIN as int");
333 }
334}
335
336impl<const LIMBS: usize> Div<NonZero<Int<LIMBS>>> for Wrapping<Int<LIMBS>> {
337 type Output = Wrapping<Int<LIMBS>>;
338
339 fn div(self, rhs: NonZero<Int<LIMBS>>) -> Self::Output {
340 Wrapping((self.0 / rhs).expect("cannot represent positive equivalent of Int::MIN as int"))
341 }
342}
343
344impl<const LIMBS: usize> Div<NonZero<Int<LIMBS>>> for &Wrapping<Int<LIMBS>> {
345 type Output = Wrapping<Int<LIMBS>>;
346
347 fn div(self, rhs: NonZero<Int<LIMBS>>) -> Self::Output {
348 *self / rhs
349 }
350}
351
352impl<const LIMBS: usize> Div<&NonZero<Int<LIMBS>>> for &Wrapping<Int<LIMBS>> {
353 type Output = Wrapping<Int<LIMBS>>;
354
355 fn div(self, rhs: &NonZero<Int<LIMBS>>) -> Self::Output {
356 *self / *rhs
357 }
358}
359
360impl<const LIMBS: usize> Div<&NonZero<Int<LIMBS>>> for Wrapping<Int<LIMBS>> {
361 type Output = Wrapping<Int<LIMBS>>;
362
363 fn div(self, rhs: &NonZero<Int<LIMBS>>) -> Self::Output {
364 self / *rhs
365 }
366}
367
368impl<const LIMBS: usize> DivAssign<&NonZero<Int<LIMBS>>> for Wrapping<Int<LIMBS>> {
369 fn div_assign(&mut self, rhs: &NonZero<Int<LIMBS>>) {
370 *self = Wrapping(
371 (self.0 / rhs).expect("cannot represent positive equivalent of Int::MIN as int"),
372 );
373 }
374}
375
376impl<const LIMBS: usize> DivAssign<NonZero<Int<LIMBS>>> for Wrapping<Int<LIMBS>> {
377 fn div_assign(&mut self, rhs: NonZero<Int<LIMBS>>) {
378 *self /= &rhs;
379 }
380}
381
382impl<const LIMBS: usize> Rem<&NonZero<Int<LIMBS>>> for &Int<LIMBS> {
383 type Output = Int<LIMBS>;
384
385 fn rem(self, rhs: &NonZero<Int<LIMBS>>) -> Self::Output {
386 *self % *rhs
387 }
388}
389
390impl<const LIMBS: usize> Rem<&NonZero<Int<LIMBS>>> for Int<LIMBS> {
391 type Output = Int<LIMBS>;
392
393 fn rem(self, rhs: &NonZero<Int<LIMBS>>) -> Self::Output {
394 self % *rhs
395 }
396}
397
398impl<const LIMBS: usize> Rem<NonZero<Int<LIMBS>>> for &Int<LIMBS> {
399 type Output = Int<LIMBS>;
400
401 fn rem(self, rhs: NonZero<Int<LIMBS>>) -> Self::Output {
402 *self % rhs
403 }
404}
405
406impl<const LIMBS: usize> Rem<NonZero<Int<LIMBS>>> for Int<LIMBS> {
407 type Output = Int<LIMBS>;
408
409 fn rem(self, rhs: NonZero<Int<LIMBS>>) -> Self::Output {
410 Self::rem(&self, &rhs)
411 }
412}
413
414impl<const LIMBS: usize> RemAssign<&NonZero<Int<LIMBS>>> for Int<LIMBS> {
415 fn rem_assign(&mut self, rhs: &NonZero<Int<LIMBS>>) {
416 *self %= *rhs
417 }
418}
419
420impl<const LIMBS: usize> RemAssign<NonZero<Int<LIMBS>>> for Int<LIMBS> {
421 fn rem_assign(&mut self, rhs: NonZero<Int<LIMBS>>) {
422 *self = *self % rhs;
423 }
424}
425
426impl<const LIMBS: usize> Rem<NonZero<Int<LIMBS>>> for Wrapping<Int<LIMBS>> {
427 type Output = Wrapping<Int<LIMBS>>;
428
429 fn rem(self, rhs: NonZero<Int<LIMBS>>) -> Self::Output {
430 Wrapping(self.0 % rhs)
431 }
432}
433
434impl<const LIMBS: usize> Rem<NonZero<Int<LIMBS>>> for &Wrapping<Int<LIMBS>> {
435 type Output = Wrapping<Int<LIMBS>>;
436
437 fn rem(self, rhs: NonZero<Int<LIMBS>>) -> Self::Output {
438 *self % rhs
439 }
440}
441
442impl<const LIMBS: usize> Rem<&NonZero<Int<LIMBS>>> for &Wrapping<Int<LIMBS>> {
443 type Output = Wrapping<Int<LIMBS>>;
444
445 fn rem(self, rhs: &NonZero<Int<LIMBS>>) -> Self::Output {
446 *self % *rhs
447 }
448}
449
450impl<const LIMBS: usize> Rem<&NonZero<Int<LIMBS>>> for Wrapping<Int<LIMBS>> {
451 type Output = Wrapping<Int<LIMBS>>;
452
453 fn rem(self, rhs: &NonZero<Int<LIMBS>>) -> Self::Output {
454 self % *rhs
455 }
456}
457
458impl<const LIMBS: usize> RemAssign<NonZero<Int<LIMBS>>> for Wrapping<Int<LIMBS>> {
459 fn rem_assign(&mut self, rhs: NonZero<Int<LIMBS>>) {
460 *self %= &rhs;
461 }
462}
463
464impl<const LIMBS: usize> RemAssign<&NonZero<Int<LIMBS>>> for Wrapping<Int<LIMBS>> {
465 fn rem_assign(&mut self, rhs: &NonZero<Int<LIMBS>>) {
466 *self = Wrapping(self.0 % rhs)
467 }
468}
469
470#[cfg(test)]
471mod tests {
472 use crate::{ConstChoice, Int, I128};
473
474 #[test]
475 fn test_checked_div() {
476 let min_plus_one = Int {
477 0: I128::MIN.0.wrapping_add(&I128::ONE.0),
478 };
479
480 let result = I128::MIN.checked_div(&I128::MIN);
483 assert_eq!(result.unwrap(), I128::ONE);
484
485 let result = I128::MIN.checked_div(&I128::MINUS_ONE);
486 assert!(bool::from(result.is_none()));
487
488 let result = I128::MIN.checked_div(&I128::ZERO);
489 assert!(bool::from(result.is_none()));
490
491 let result = I128::MIN.checked_div(&I128::ONE);
492 assert_eq!(result.unwrap(), I128::MIN);
493
494 let result = I128::MIN.checked_div(&I128::MAX);
495 assert_eq!(result.unwrap(), I128::MINUS_ONE);
496
497 let result = I128::MINUS_ONE.checked_div(&I128::MIN);
500 assert_eq!(result.unwrap(), I128::ZERO);
501
502 let result = I128::MINUS_ONE.checked_div(&I128::MINUS_ONE);
503 assert_eq!(result.unwrap(), I128::ONE);
504
505 let result = I128::MINUS_ONE.checked_div(&I128::ZERO);
506 assert!(bool::from(result.is_none()));
507
508 let result = I128::MINUS_ONE.checked_div(&I128::ONE);
509 assert_eq!(result.unwrap(), I128::MINUS_ONE);
510
511 let result = I128::MINUS_ONE.checked_div(&I128::MAX);
512 assert_eq!(result.unwrap(), I128::ZERO);
513
514 let result = I128::ZERO.checked_div(&I128::MIN);
517 assert_eq!(result.unwrap(), I128::ZERO);
518
519 let result = I128::ZERO.checked_div(&I128::MINUS_ONE);
520 assert_eq!(result.unwrap(), I128::ZERO);
521
522 let result = I128::ZERO.checked_div(&I128::ZERO);
523 assert!(bool::from(result.is_none()));
524
525 let result = I128::ZERO.checked_div(&I128::ONE);
526 assert_eq!(result.unwrap(), I128::ZERO);
527
528 let result = I128::ZERO.checked_div(&I128::MAX);
529 assert_eq!(result.unwrap(), I128::ZERO);
530
531 let result = I128::ONE.checked_div(&I128::MIN);
534 assert_eq!(result.unwrap(), I128::ZERO);
535
536 let result = I128::ONE.checked_div(&I128::MINUS_ONE);
537 assert_eq!(result.unwrap(), I128::MINUS_ONE);
538
539 let result = I128::ONE.checked_div(&I128::ZERO);
540 assert!(bool::from(result.is_none()));
541
542 let result = I128::ONE.checked_div(&I128::ONE);
543 assert_eq!(result.unwrap(), I128::ONE);
544
545 let result = I128::ONE.checked_div(&I128::MAX);
546 assert_eq!(result.unwrap(), I128::ZERO);
547
548 let result = I128::MAX.checked_div(&I128::MIN);
551 assert_eq!(result.unwrap(), I128::ZERO);
552
553 let result = I128::MAX.checked_div(&I128::MINUS_ONE);
554 assert_eq!(result.unwrap(), min_plus_one);
555
556 let result = I128::MAX.checked_div(&I128::ZERO);
557 assert!(bool::from(result.is_none()));
558
559 let result = I128::MAX.checked_div(&I128::ONE);
560 assert_eq!(result.unwrap(), I128::MAX);
561
562 let result = I128::MAX.checked_div(&I128::MAX);
563 assert_eq!(result.unwrap(), I128::ONE);
564 }
565
566 #[test]
567 fn test_checked_div_floor() {
568 assert_eq!(
569 I128::from(8).checked_div_floor(&I128::from(3)).unwrap(),
570 I128::from(2)
571 );
572 assert_eq!(
573 I128::from(-8).checked_div_floor(&I128::from(3)).unwrap(),
574 I128::from(-3)
575 );
576 assert_eq!(
577 I128::from(8).checked_div_floor(&I128::from(-3)).unwrap(),
578 I128::from(-3)
579 );
580 assert_eq!(
581 I128::from(-8).checked_div_floor(&I128::from(-3)).unwrap(),
582 I128::from(2)
583 );
584 }
585
586 #[test]
587 fn test_checked_div_mod_floor() {
588 let (quotient, remainder) =
589 I128::MIN.checked_div_rem_floor(&I128::MINUS_ONE.to_nz().unwrap());
590 assert_eq!(quotient.is_some(), ConstChoice::FALSE);
591 assert_eq!(remainder, I128::ZERO);
592 }
593}