1use core::ops::{Div, DivAssign, Rem, RemAssign};
3
4use crate::{Choice, Int, NonZero, Uint, Wrapping};
5
6impl<const LIMBS: usize> Int<LIMBS> {
8 #[inline]
9 const fn div_rem_base_unsigned<const RHS_LIMBS: usize>(
13 &self,
14 rhs: &NonZero<Uint<RHS_LIMBS>>,
15 ) -> (Uint<LIMBS>, Uint<RHS_LIMBS>, Choice) {
16 let (lhs_mag, lhs_sgn) = self.abs_sign();
17 let (quotient, remainder) = lhs_mag.div_rem(rhs);
18 (quotient, remainder, lhs_sgn)
19 }
20
21 #[must_use]
36 pub const fn div_rem_unsigned<const RHS_LIMBS: usize>(
37 &self,
38 rhs: &NonZero<Uint<RHS_LIMBS>>,
39 ) -> (Self, Int<RHS_LIMBS>) {
40 let (quotient, remainder, lhs_sgn) = self.div_rem_base_unsigned(rhs);
41 (
42 Self(quotient).wrapping_neg_if(lhs_sgn),
43 Int::new_from_abs_sign(remainder, lhs_sgn).expect_copied("no overflow; always fits"),
44 )
45 }
46
47 #[must_use]
50 pub const fn div_unsigned<const RHS_LIMBS: usize>(
51 &self,
52 rhs: &NonZero<Uint<RHS_LIMBS>>,
53 ) -> Self {
54 self.div_rem_unsigned(rhs).0
55 }
56
57 #[must_use]
60 pub const fn rem_unsigned<const RHS_LIMBS: usize>(
61 &self,
62 rhs: &NonZero<Uint<RHS_LIMBS>>,
63 ) -> Int<RHS_LIMBS> {
64 self.div_rem_unsigned(rhs).1
65 }
66}
67
68impl<const LIMBS: usize> Int<LIMBS> {
70 #[inline]
71 const fn div_rem_base_unsigned_vartime<const RHS_LIMBS: usize>(
78 &self,
79 rhs: &NonZero<Uint<RHS_LIMBS>>,
80 ) -> (Uint<LIMBS>, Uint<RHS_LIMBS>, Choice) {
81 let (lhs_mag, lhs_sgn) = self.abs_sign();
82 let (quotient, remainder) = lhs_mag.div_rem_vartime(rhs);
83 (quotient, remainder, lhs_sgn)
84 }
85
86 #[must_use]
93 pub const fn div_rem_unsigned_vartime<const RHS_LIMBS: usize>(
94 &self,
95 rhs: &NonZero<Uint<RHS_LIMBS>>,
96 ) -> (Self, Int<RHS_LIMBS>) {
97 let (quotient, remainder, lhs_sgn) = self.div_rem_base_unsigned_vartime(rhs);
98 (
99 Self(quotient).wrapping_neg_if(lhs_sgn),
100 remainder.as_int().wrapping_neg_if(lhs_sgn),
101 )
102 }
103
104 #[must_use]
111 pub const fn div_unsigned_vartime<const RHS_LIMBS: usize>(
112 &self,
113 rhs: &NonZero<Uint<RHS_LIMBS>>,
114 ) -> Self {
115 self.div_rem_unsigned_vartime(rhs).0
116 }
117
118 #[must_use]
125 pub const fn rem_unsigned_vartime<const RHS_LIMBS: usize>(
126 &self,
127 rhs: &NonZero<Uint<RHS_LIMBS>>,
128 ) -> Int<RHS_LIMBS> {
129 self.div_rem_unsigned_vartime(rhs).1
130 }
131}
132
133impl<const LIMBS: usize> Int<LIMBS> {
135 #[must_use]
154 pub fn div_rem_floor_unsigned<const RHS_LIMBS: usize>(
155 &self,
156 rhs: &NonZero<Uint<RHS_LIMBS>>,
157 ) -> (Self, Uint<RHS_LIMBS>) {
158 let (quotient, remainder, lhs_sgn) = self.div_rem_base_unsigned(rhs);
159
160 let modify = remainder.is_nonzero().and(lhs_sgn);
162 let quotient = Uint::select("ient, "ient.wrapping_add(&Uint::ONE), modify);
163
164 let remainder = Uint::select(&remainder, &rhs.wrapping_sub(&remainder), modify);
166
167 let quotient = Self(quotient).wrapping_neg_if(lhs_sgn);
169
170 (quotient, remainder)
171 }
172
173 #[must_use]
189 pub fn div_floor_unsigned<const RHS_LIMBS: usize>(
190 &self,
191 rhs: &NonZero<Uint<RHS_LIMBS>>,
192 ) -> Self {
193 let (q, _) = self.div_rem_floor_unsigned(rhs);
194 q
195 }
196
197 #[must_use]
212 pub fn normalized_rem<const RHS_LIMBS: usize>(
213 &self,
214 rhs: &NonZero<Uint<RHS_LIMBS>>,
215 ) -> Uint<RHS_LIMBS> {
216 let (_, r) = self.div_rem_floor_unsigned(rhs);
217 r
218 }
219}
220
221impl<const LIMBS: usize> Int<LIMBS> {
223 #[must_use]
230 pub fn div_rem_floor_unsigned_vartime<const RHS_LIMBS: usize>(
231 &self,
232 rhs: &NonZero<Uint<RHS_LIMBS>>,
233 ) -> (Self, Uint<RHS_LIMBS>) {
234 let (quotient, remainder, lhs_sgn) = self.div_rem_base_unsigned_vartime(rhs);
235
236 let modify = remainder.is_nonzero().and(lhs_sgn);
238 let quotient = Uint::select("ient, "ient.wrapping_add(&Uint::ONE), modify);
239
240 let remainder = Uint::select(&remainder, &rhs.wrapping_sub(&remainder), modify);
242
243 let quotient = Self(quotient).wrapping_neg_if(lhs_sgn);
245
246 (quotient, remainder)
247 }
248
249 #[must_use]
256 pub fn div_floor_unsigned_vartime<const RHS_LIMBS: usize>(
257 &self,
258 rhs: &NonZero<Uint<RHS_LIMBS>>,
259 ) -> Self {
260 let (q, _) = self.div_rem_floor_unsigned_vartime(rhs);
261 q
262 }
263
264 #[must_use]
271 pub fn normalized_rem_vartime<const RHS_LIMBS: usize>(
272 &self,
273 rhs: &NonZero<Uint<RHS_LIMBS>>,
274 ) -> Uint<RHS_LIMBS> {
275 let (_, r) = self.div_rem_floor_unsigned_vartime(rhs);
276 r
277 }
278}
279
280impl<const LIMBS: usize, const RHS_LIMBS: usize> Div<&NonZero<Uint<RHS_LIMBS>>> for &Int<LIMBS> {
281 type Output = Int<LIMBS>;
282
283 fn div(self, rhs: &NonZero<Uint<RHS_LIMBS>>) -> Self::Output {
284 *self / *rhs
285 }
286}
287
288impl<const LIMBS: usize, const RHS_LIMBS: usize> Div<&NonZero<Uint<RHS_LIMBS>>> for Int<LIMBS> {
289 type Output = Int<LIMBS>;
290
291 fn div(self, rhs: &NonZero<Uint<RHS_LIMBS>>) -> Self::Output {
292 self / *rhs
293 }
294}
295
296impl<const LIMBS: usize, const RHS_LIMBS: usize> Div<NonZero<Uint<RHS_LIMBS>>> for &Int<LIMBS> {
297 type Output = Int<LIMBS>;
298
299 fn div(self, rhs: NonZero<Uint<RHS_LIMBS>>) -> Self::Output {
300 *self / rhs
301 }
302}
303
304impl<const LIMBS: usize, const RHS_LIMBS: usize> Div<NonZero<Uint<RHS_LIMBS>>> for Int<LIMBS> {
305 type Output = Int<LIMBS>;
306
307 fn div(self, rhs: NonZero<Uint<RHS_LIMBS>>) -> Self::Output {
308 self.div_unsigned(&rhs)
309 }
310}
311
312impl<const LIMBS: usize> DivAssign<&NonZero<Uint<LIMBS>>> for Int<LIMBS> {
313 fn div_assign(&mut self, rhs: &NonZero<Uint<LIMBS>>) {
314 *self /= *rhs;
315 }
316}
317
318impl<const LIMBS: usize> DivAssign<NonZero<Uint<LIMBS>>> for Int<LIMBS> {
319 fn div_assign(&mut self, rhs: NonZero<Uint<LIMBS>>) {
320 *self = *self / rhs;
321 }
322}
323
324impl<const LIMBS: usize, const RHS_LIMBS: usize> Div<NonZero<Uint<RHS_LIMBS>>>
325 for Wrapping<Int<LIMBS>>
326{
327 type Output = Wrapping<Int<LIMBS>>;
328
329 fn div(self, rhs: NonZero<Uint<RHS_LIMBS>>) -> Self::Output {
330 Wrapping(self.0 / rhs)
331 }
332}
333
334impl<const LIMBS: usize, const RHS_LIMBS: usize> Div<NonZero<Uint<RHS_LIMBS>>>
335 for &Wrapping<Int<LIMBS>>
336{
337 type Output = Wrapping<Int<LIMBS>>;
338
339 fn div(self, rhs: NonZero<Uint<RHS_LIMBS>>) -> Self::Output {
340 *self / rhs
341 }
342}
343
344impl<const LIMBS: usize, const RHS_LIMBS: usize> Div<&NonZero<Uint<RHS_LIMBS>>>
345 for &Wrapping<Int<LIMBS>>
346{
347 type Output = Wrapping<Int<LIMBS>>;
348
349 fn div(self, rhs: &NonZero<Uint<RHS_LIMBS>>) -> Self::Output {
350 *self / *rhs
351 }
352}
353
354impl<const LIMBS: usize, const RHS_LIMBS: usize> Div<&NonZero<Uint<RHS_LIMBS>>>
355 for Wrapping<Int<LIMBS>>
356{
357 type Output = Wrapping<Int<LIMBS>>;
358
359 fn div(self, rhs: &NonZero<Uint<RHS_LIMBS>>) -> Self::Output {
360 self / *rhs
361 }
362}
363
364impl<const LIMBS: usize> DivAssign<&NonZero<Uint<LIMBS>>> for Wrapping<Int<LIMBS>> {
365 fn div_assign(&mut self, rhs: &NonZero<Uint<LIMBS>>) {
366 *self = Wrapping(self.0 / rhs);
367 }
368}
369
370impl<const LIMBS: usize> DivAssign<NonZero<Uint<LIMBS>>> for Wrapping<Int<LIMBS>> {
371 fn div_assign(&mut self, rhs: NonZero<Uint<LIMBS>>) {
372 *self /= &rhs;
373 }
374}
375
376impl<const LIMBS: usize, const RHS_LIMBS: usize> Rem<&NonZero<Uint<RHS_LIMBS>>> for &Int<LIMBS> {
377 type Output = Int<RHS_LIMBS>;
378
379 fn rem(self, rhs: &NonZero<Uint<RHS_LIMBS>>) -> Self::Output {
380 *self % *rhs
381 }
382}
383
384impl<const LIMBS: usize, const RHS_LIMBS: usize> Rem<&NonZero<Uint<RHS_LIMBS>>> for Int<LIMBS> {
385 type Output = Int<RHS_LIMBS>;
386
387 fn rem(self, rhs: &NonZero<Uint<RHS_LIMBS>>) -> Self::Output {
388 self % *rhs
389 }
390}
391
392impl<const LIMBS: usize, const RHS_LIMBS: usize> Rem<NonZero<Uint<RHS_LIMBS>>> for &Int<LIMBS> {
393 type Output = Int<RHS_LIMBS>;
394
395 fn rem(self, rhs: NonZero<Uint<RHS_LIMBS>>) -> Self::Output {
396 *self % rhs
397 }
398}
399
400impl<const LIMBS: usize, const RHS_LIMBS: usize> Rem<NonZero<Uint<RHS_LIMBS>>> for Int<LIMBS> {
401 type Output = Int<RHS_LIMBS>;
402
403 fn rem(self, rhs: NonZero<Uint<RHS_LIMBS>>) -> Self::Output {
404 Self::rem_unsigned(&self, &rhs)
405 }
406}
407
408impl<const LIMBS: usize> RemAssign<&NonZero<Uint<LIMBS>>> for Int<LIMBS> {
409 fn rem_assign(&mut self, rhs: &NonZero<Uint<LIMBS>>) {
410 *self %= *rhs;
411 }
412}
413
414impl<const LIMBS: usize> RemAssign<NonZero<Uint<LIMBS>>> for Int<LIMBS> {
415 fn rem_assign(&mut self, rhs: NonZero<Uint<LIMBS>>) {
416 *self = *self % rhs;
417 }
418}
419
420impl<const LIMBS: usize, const RHS_LIMBS: usize> Rem<NonZero<Uint<RHS_LIMBS>>>
421 for Wrapping<Int<LIMBS>>
422{
423 type Output = Wrapping<Int<RHS_LIMBS>>;
424
425 fn rem(self, rhs: NonZero<Uint<RHS_LIMBS>>) -> Self::Output {
426 Wrapping(self.0 % rhs)
427 }
428}
429
430impl<const LIMBS: usize, const RHS_LIMBS: usize> Rem<NonZero<Uint<RHS_LIMBS>>>
431 for &Wrapping<Int<LIMBS>>
432{
433 type Output = Wrapping<Int<RHS_LIMBS>>;
434
435 fn rem(self, rhs: NonZero<Uint<RHS_LIMBS>>) -> Self::Output {
436 *self % rhs
437 }
438}
439
440impl<const LIMBS: usize, const RHS_LIMBS: usize> Rem<&NonZero<Uint<RHS_LIMBS>>>
441 for &Wrapping<Int<LIMBS>>
442{
443 type Output = Wrapping<Int<RHS_LIMBS>>;
444
445 fn rem(self, rhs: &NonZero<Uint<RHS_LIMBS>>) -> Self::Output {
446 *self % *rhs
447 }
448}
449
450impl<const LIMBS: usize, const RHS_LIMBS: usize> Rem<&NonZero<Uint<RHS_LIMBS>>>
451 for Wrapping<Int<LIMBS>>
452{
453 type Output = Wrapping<Int<RHS_LIMBS>>;
454
455 fn rem(self, rhs: &NonZero<Uint<RHS_LIMBS>>) -> Self::Output {
456 self % *rhs
457 }
458}
459
460impl<const LIMBS: usize> RemAssign<NonZero<Uint<LIMBS>>> for Wrapping<Int<LIMBS>> {
461 fn rem_assign(&mut self, rhs: NonZero<Uint<LIMBS>>) {
462 *self %= &rhs;
463 }
464}
465
466impl<const LIMBS: usize> RemAssign<&NonZero<Uint<LIMBS>>> for Wrapping<Int<LIMBS>> {
467 fn rem_assign(&mut self, rhs: &NonZero<Uint<LIMBS>>) {
468 *self = Wrapping(self.0 % rhs);
469 }
470}
471
472#[cfg(test)]
473mod tests {
474 #[cfg(feature = "rand_core")]
475 use {
476 crate::{I1024, Random, U512, U1024},
477 chacha20::ChaCha8Rng,
478 rand_core::SeedableRng,
479 };
480
481 use crate::{I128, U128};
482
483 #[test]
484 fn test_div_unsigned() {
485 assert_eq!(I128::MIN / U128::ONE.to_nz().unwrap(), I128::MIN);
487 assert_eq!(I128::MIN / U128::MAX.to_nz().unwrap(), I128::ZERO);
488
489 assert_eq!(
491 I128::MINUS_ONE / U128::ONE.to_nz().unwrap(),
492 I128::MINUS_ONE
493 );
494 assert_eq!(I128::MINUS_ONE / U128::MAX.to_nz().unwrap(), I128::ZERO);
495
496 assert_eq!(I128::ZERO / U128::ONE.to_nz().unwrap(), I128::ZERO);
498 assert_eq!(I128::ZERO / U128::MAX.to_nz().unwrap(), I128::ZERO);
499
500 assert_eq!(I128::ONE / U128::ONE.to_nz().unwrap(), I128::ONE);
502 assert_eq!(I128::ONE / U128::MAX.to_nz().unwrap(), I128::ZERO);
503
504 assert_eq!(I128::MAX / U128::ONE.to_nz().unwrap(), I128::MAX);
506 assert_eq!(I128::MAX / U128::MAX.to_nz().unwrap(), I128::ZERO);
507 }
508
509 #[cfg(feature = "rand_core")]
511 #[test]
512 fn test_div_ct_vs_vt() {
513 let mut rng = ChaCha8Rng::from_seed([7u8; 32]);
514 for _ in 0..50 {
515 let num = I1024::random_from_rng(&mut rng);
516 let denom = U1024::from(&U512::random_from_rng(&mut rng))
517 .to_nz()
518 .unwrap();
519
520 assert_eq!(num.div_unsigned(&denom), num.div_unsigned_vartime(&denom));
521 }
522 }
523
524 #[test]
525 fn test_div_rem_floor_unsigned() {
526 assert_eq!(
528 I128::MIN.div_rem_floor_unsigned(&U128::ONE.to_nz().unwrap()),
529 (I128::MIN, U128::ZERO)
530 );
531 assert_eq!(
532 I128::MIN.div_rem_floor_unsigned(&U128::MAX.to_nz().unwrap()),
533 (
534 I128::MINUS_ONE,
535 I128::MIN.as_uint().wrapping_sub(&U128::ONE)
536 )
537 );
538
539 assert_eq!(
541 I128::MINUS_ONE.div_rem_floor_unsigned(&U128::ONE.to_nz().unwrap()),
542 (I128::MINUS_ONE, U128::ZERO)
543 );
544 assert_eq!(
545 I128::MINUS_ONE.div_rem_floor_unsigned(&U128::MAX.to_nz().unwrap()),
546 (I128::MINUS_ONE, U128::MAX.wrapping_sub(&U128::ONE))
547 );
548
549 assert_eq!(
551 I128::ZERO.div_rem_floor_unsigned(&U128::ONE.to_nz().unwrap()),
552 (I128::ZERO, U128::ZERO)
553 );
554 assert_eq!(
555 I128::ZERO.div_rem_floor_unsigned(&U128::MAX.to_nz().unwrap()),
556 (I128::ZERO, U128::ZERO)
557 );
558
559 assert_eq!(
561 I128::ONE.div_rem_floor_unsigned(&U128::ONE.to_nz().unwrap()),
562 (I128::ONE, U128::ZERO)
563 );
564 assert_eq!(
565 I128::ONE.div_rem_floor_unsigned(&U128::MAX.to_nz().unwrap()),
566 (I128::ZERO, U128::ONE)
567 );
568
569 assert_eq!(
571 I128::MAX.div_rem_floor_unsigned(&U128::ONE.to_nz().unwrap()),
572 (I128::MAX, U128::ZERO)
573 );
574 assert_eq!(
575 I128::MAX.div_rem_floor_unsigned(&U128::MAX.to_nz().unwrap()),
576 (I128::ZERO, *I128::MAX.as_uint())
577 );
578 }
579
580 #[cfg(feature = "rand_core")]
582 #[test]
583 fn test_div_floor_ct_vs_vt() {
584 let mut rng = ChaCha8Rng::from_seed([7u8; 32]);
585 for _ in 0..50 {
586 let num = I1024::random_from_rng(&mut rng);
587 let denom = U1024::from(&U512::random_from_rng(&mut rng))
588 .to_nz()
589 .unwrap();
590
591 assert_eq!(
592 num.div_floor_unsigned(&denom),
593 num.div_floor_unsigned_vartime(&denom)
594 );
595 }
596 }
597}