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 remainder.as_int().wrapping_neg_if(lhs_sgn),
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, I256, U128};
482
483 #[test]
485 fn test_div_rem_unsigned_large_remainder() {
486 let num =
487 I256::from_be_hex("eed8f6c7a5b1a65031ebc9b7a93492e89f282d49e75d25607a5693b3d8ae2e87");
488 let denom = U128::from_be_hex("de157f812521c55eccf9a903b31e4a34")
489 .to_nz()
490 .unwrap();
491 let (q, r) = num.div_rem_unsigned(&denom);
492 let (q_vt, r_vt) = num.div_rem_unsigned_vartime(&denom);
493 assert_eq!(q, q_vt);
494 assert_eq!(r, r_vt);
495
496 let (q2, r2) = I128::MIN.div_rem_unsigned(&U128::MAX.to_nz().unwrap());
497 let (q2_vt, r2_vt) = I128::MIN.div_rem_unsigned_vartime(&U128::MAX.to_nz().unwrap());
498 assert_eq!(q2, q2_vt);
499 assert_eq!(r2, r2_vt);
500 }
501
502 #[test]
503 fn test_div_unsigned() {
504 assert_eq!(I128::MIN / U128::ONE.to_nz().unwrap(), I128::MIN);
506 assert_eq!(I128::MIN / U128::MAX.to_nz().unwrap(), I128::ZERO);
507
508 assert_eq!(
510 I128::MINUS_ONE / U128::ONE.to_nz().unwrap(),
511 I128::MINUS_ONE
512 );
513 assert_eq!(I128::MINUS_ONE / U128::MAX.to_nz().unwrap(), I128::ZERO);
514
515 assert_eq!(I128::ZERO / U128::ONE.to_nz().unwrap(), I128::ZERO);
517 assert_eq!(I128::ZERO / U128::MAX.to_nz().unwrap(), I128::ZERO);
518
519 assert_eq!(I128::ONE / U128::ONE.to_nz().unwrap(), I128::ONE);
521 assert_eq!(I128::ONE / U128::MAX.to_nz().unwrap(), I128::ZERO);
522
523 assert_eq!(I128::MAX / U128::ONE.to_nz().unwrap(), I128::MAX);
525 assert_eq!(I128::MAX / U128::MAX.to_nz().unwrap(), I128::ZERO);
526 }
527
528 #[cfg(feature = "rand_core")]
530 #[test]
531 fn test_div_ct_vs_vt() {
532 let mut rng = ChaCha8Rng::from_seed([7u8; 32]);
533 for _ in 0..50 {
534 let num = I1024::random_from_rng(&mut rng);
535 let denom = U1024::from(&U512::random_from_rng(&mut rng))
536 .to_nz()
537 .unwrap();
538
539 assert_eq!(num.div_unsigned(&denom), num.div_unsigned_vartime(&denom));
540 }
541 }
542
543 #[test]
544 fn test_div_rem_floor_unsigned() {
545 assert_eq!(
547 I128::MIN.div_rem_floor_unsigned(&U128::ONE.to_nz().unwrap()),
548 (I128::MIN, U128::ZERO)
549 );
550 assert_eq!(
551 I128::MIN.div_rem_floor_unsigned(&U128::MAX.to_nz().unwrap()),
552 (
553 I128::MINUS_ONE,
554 I128::MIN.as_uint().wrapping_sub(&U128::ONE)
555 )
556 );
557
558 assert_eq!(
560 I128::MINUS_ONE.div_rem_floor_unsigned(&U128::ONE.to_nz().unwrap()),
561 (I128::MINUS_ONE, U128::ZERO)
562 );
563 assert_eq!(
564 I128::MINUS_ONE.div_rem_floor_unsigned(&U128::MAX.to_nz().unwrap()),
565 (I128::MINUS_ONE, U128::MAX.wrapping_sub(&U128::ONE))
566 );
567
568 assert_eq!(
570 I128::ZERO.div_rem_floor_unsigned(&U128::ONE.to_nz().unwrap()),
571 (I128::ZERO, U128::ZERO)
572 );
573 assert_eq!(
574 I128::ZERO.div_rem_floor_unsigned(&U128::MAX.to_nz().unwrap()),
575 (I128::ZERO, U128::ZERO)
576 );
577
578 assert_eq!(
580 I128::ONE.div_rem_floor_unsigned(&U128::ONE.to_nz().unwrap()),
581 (I128::ONE, U128::ZERO)
582 );
583 assert_eq!(
584 I128::ONE.div_rem_floor_unsigned(&U128::MAX.to_nz().unwrap()),
585 (I128::ZERO, U128::ONE)
586 );
587
588 assert_eq!(
590 I128::MAX.div_rem_floor_unsigned(&U128::ONE.to_nz().unwrap()),
591 (I128::MAX, U128::ZERO)
592 );
593 assert_eq!(
594 I128::MAX.div_rem_floor_unsigned(&U128::MAX.to_nz().unwrap()),
595 (I128::ZERO, *I128::MAX.as_uint())
596 );
597 }
598
599 #[cfg(feature = "rand_core")]
601 #[test]
602 fn test_div_floor_ct_vs_vt() {
603 let mut rng = ChaCha8Rng::from_seed([7u8; 32]);
604 for _ in 0..50 {
605 let num = I1024::random_from_rng(&mut rng);
606 let denom = U1024::from(&U512::random_from_rng(&mut rng))
607 .to_nz()
608 .unwrap();
609
610 assert_eq!(
611 num.div_floor_unsigned(&denom),
612 num.div_floor_unsigned_vartime(&denom)
613 );
614 }
615 }
616}