1use crate::core_type::D38;
38
39impl<const SCALE: u32> D38<SCALE> {
40 #[inline]
69 #[must_use]
70 pub fn checked_mul(self, rhs: Self) -> Option<Self> {
71 crate::mg_divide::mul_div_pow10::<SCALE>(self.0, rhs.0).map(Self)
72 }
73
74 #[inline]
96 #[must_use]
97 pub fn wrapping_mul(self, rhs: Self) -> Self {
98 match crate::mg_divide::mul_div_pow10::<SCALE>(self.0, rhs.0) {
99 Some(q) => Self(q),
100 None => Self(
101 self.0
102 .wrapping_mul(rhs.0)
103 .wrapping_div(Self::multiplier()),
104 ),
105 }
106 }
107
108 #[inline]
128 #[must_use]
129 pub fn saturating_mul(self, rhs: Self) -> Self {
130 if let Some(q) = crate::mg_divide::mul_div_pow10::<SCALE>(self.0, rhs.0) { Self(q) } else {
131 let neg = (self.0 < 0) ^ (rhs.0 < 0);
134 if neg { Self::MIN } else { Self::MAX }
135 }
136 }
137
138 #[inline]
156 #[must_use]
157 pub fn overflowing_mul(self, rhs: Self) -> (Self, bool) {
158 match crate::mg_divide::mul_div_pow10::<SCALE>(self.0, rhs.0) {
159 Some(q) => (Self(q), false),
160 None => (self.wrapping_mul(rhs), true),
161 }
162 }
163
164 #[inline]
194 #[must_use]
195 pub fn checked_div(self, rhs: Self) -> Option<Self> {
196 crate::mg_divide::div_pow10_div::<SCALE>(self.0, rhs.0).map(Self)
197 }
198
199 #[inline]
223 #[must_use]
224 pub fn wrapping_div(self, rhs: Self) -> Self {
225 assert!(rhs.0 != 0, "attempt to divide by zero");
226 match crate::mg_divide::div_pow10_div::<SCALE>(self.0, rhs.0) {
227 Some(q) => Self(q),
228 None => Self(
229 self.0
230 .wrapping_mul(Self::multiplier())
231 .wrapping_div(rhs.0),
232 ),
233 }
234 }
235
236 #[inline]
262 #[must_use]
263 pub fn saturating_div(self, rhs: Self) -> Self {
264 assert!(rhs.0 != 0, "attempt to divide by zero");
265 if let Some(q) = crate::mg_divide::div_pow10_div::<SCALE>(self.0, rhs.0) { Self(q) } else {
266 let neg = (self.0 < 0) ^ (rhs.0 < 0);
268 if neg { Self::MIN } else { Self::MAX }
269 }
270 }
271
272 #[inline]
296 #[must_use]
297 pub fn overflowing_div(self, rhs: Self) -> (Self, bool) {
298 assert!(rhs.0 != 0, "attempt to divide by zero");
299 match crate::mg_divide::div_pow10_div::<SCALE>(self.0, rhs.0) {
300 Some(q) => (Self(q), false),
301 None => (self.wrapping_div(rhs), true),
302 }
303 }
304
305}
306
307#[cfg(test)]
308#[allow(clippy::arithmetic_side_effects)]
309mod tests {
310 use crate::core_type::{D38, D38s12};
311
312 fn neg_one() -> D38s12 {
314 -D38s12::ONE
315 }
316
317 fn two() -> D38s12 {
319 D38s12::from_bits(2_000_000_000_000)
320 }
321
322 fn three() -> D38s12 {
324 D38s12::from_bits(3_000_000_000_000)
325 }
326
327 #[test]
330 fn checked_add_normal() {
331 assert_eq!(D38s12::ONE.checked_add(D38s12::ONE), Some(two()));
332 }
333
334 #[test]
335 fn checked_add_overflow_returns_none() {
336 assert_eq!(D38s12::MAX.checked_add(D38s12::ONE), None);
338 assert_eq!(
340 D38s12::MAX.checked_add(D38s12::from_bits(1)),
341 None
342 );
343 }
344
345 #[test]
346 fn checked_add_negative_overflow_returns_none() {
347 assert_eq!(D38s12::MIN.checked_add(neg_one()), None);
348 assert_eq!(
350 D38s12::MIN.checked_add(D38s12::from_bits(-1)),
351 None
352 );
353 }
354
355 #[test]
356 fn wrapping_add_normal_matches_op() {
357 assert_eq!(D38s12::ONE.wrapping_add(D38s12::ONE), two());
358 }
359
360 #[test]
361 fn wrapping_add_overflow_wraps_to_min() {
362 assert_eq!(
364 D38s12::MAX.wrapping_add(D38s12::from_bits(1)),
365 D38s12::MIN
366 );
367 }
368
369 #[test]
370 fn wrapping_add_negative_overflow_wraps_to_max() {
371 assert_eq!(
373 D38s12::MIN.wrapping_add(D38s12::from_bits(-1)),
374 D38s12::MAX
375 );
376 }
377
378 #[test]
379 fn saturating_add_normal_matches_op() {
380 assert_eq!(D38s12::ONE.saturating_add(D38s12::ONE), two());
381 }
382
383 #[test]
384 fn saturating_add_overflow_clamps_to_max() {
385 assert_eq!(D38s12::MAX.saturating_add(D38s12::ONE), D38s12::MAX);
386 }
387
388 #[test]
389 fn saturating_add_negative_overflow_clamps_to_min() {
390 assert_eq!(D38s12::MIN.saturating_add(neg_one()), D38s12::MIN);
391 }
392
393 #[test]
394 fn overflowing_add_normal_no_overflow() {
395 assert_eq!(
396 D38s12::ONE.overflowing_add(D38s12::ONE),
397 (two(), false)
398 );
399 }
400
401 #[test]
402 fn overflowing_add_overflow_flagged() {
403 assert_eq!(
405 D38s12::MAX.overflowing_add(D38s12::from_bits(1)),
406 (D38s12::MIN, true)
407 );
408 }
409
410 #[test]
411 fn overflowing_add_negative_overflow_flagged() {
412 assert_eq!(
414 D38s12::MIN.overflowing_add(D38s12::from_bits(-1)),
415 (D38s12::MAX, true)
416 );
417 }
418
419 #[test]
422 fn checked_sub_normal() {
423 assert_eq!(three().checked_sub(D38s12::ONE), Some(two()));
424 }
425
426 #[test]
427 fn checked_sub_underflow_returns_none() {
428 assert_eq!(D38s12::MIN.checked_sub(D38s12::ONE), None);
429 }
430
431 #[test]
432 fn checked_sub_positive_overflow_returns_none() {
433 assert_eq!(D38s12::MAX.checked_sub(neg_one()), None);
435 }
436
437 #[test]
438 fn wrapping_sub_normal() {
439 assert_eq!(three().wrapping_sub(D38s12::ONE), two());
440 }
441
442 #[test]
443 fn wrapping_sub_underflow_wraps_to_max() {
444 assert_eq!(
446 D38s12::MIN.wrapping_sub(D38s12::from_bits(1)),
447 D38s12::MAX
448 );
449 }
450
451 #[test]
452 fn saturating_sub_normal() {
453 assert_eq!(three().saturating_sub(D38s12::ONE), two());
454 }
455
456 #[test]
457 fn saturating_sub_underflow_clamps_to_min() {
458 assert_eq!(D38s12::MIN.saturating_sub(D38s12::ONE), D38s12::MIN);
459 }
460
461 #[test]
462 fn saturating_sub_overflow_clamps_to_max() {
463 assert_eq!(D38s12::MAX.saturating_sub(neg_one()), D38s12::MAX);
465 }
466
467 #[test]
468 fn overflowing_sub_normal() {
469 assert_eq!(
470 three().overflowing_sub(D38s12::ONE),
471 (two(), false)
472 );
473 }
474
475 #[test]
476 fn overflowing_sub_underflow_flagged() {
477 assert_eq!(
479 D38s12::MIN.overflowing_sub(D38s12::from_bits(1)),
480 (D38s12::MAX, true)
481 );
482 }
483
484 #[test]
487 fn checked_neg_normal() {
488 assert_eq!(D38s12::ONE.checked_neg(), Some(neg_one()));
489 assert_eq!(neg_one().checked_neg(), Some(D38s12::ONE));
490 assert_eq!(D38s12::ZERO.checked_neg(), Some(D38s12::ZERO));
491 }
492
493 #[test]
494 fn checked_neg_min_returns_none() {
495 assert_eq!(D38s12::MIN.checked_neg(), None);
496 }
497
498 #[test]
499 fn checked_neg_max_succeeds() {
500 let neg_max = D38s12::from_bits(-i128::MAX);
502 assert_eq!(D38s12::MAX.checked_neg(), Some(neg_max));
503 }
504
505 #[test]
506 fn wrapping_neg_normal() {
507 assert_eq!(D38s12::ONE.wrapping_neg(), neg_one());
508 assert_eq!(D38s12::ZERO.wrapping_neg(), D38s12::ZERO);
509 }
510
511 #[test]
512 fn wrapping_neg_min_returns_min() {
513 assert_eq!(D38s12::MIN.wrapping_neg(), D38s12::MIN);
515 }
516
517 #[test]
518 fn saturating_neg_normal() {
519 assert_eq!(D38s12::ONE.saturating_neg(), neg_one());
520 assert_eq!(D38s12::ZERO.saturating_neg(), D38s12::ZERO);
521 }
522
523 #[test]
524 fn saturating_neg_min_returns_max() {
525 assert_eq!(D38s12::MIN.saturating_neg(), D38s12::MAX);
526 }
527
528 #[test]
529 fn overflowing_neg_normal() {
530 assert_eq!(
531 D38s12::ONE.overflowing_neg(),
532 (neg_one(), false)
533 );
534 assert_eq!(
535 D38s12::ZERO.overflowing_neg(),
536 (D38s12::ZERO, false)
537 );
538 }
539
540 #[test]
541 fn overflowing_neg_min_flagged() {
542 assert_eq!(
543 D38s12::MIN.overflowing_neg(),
544 (D38s12::MIN, true)
545 );
546 }
547
548 #[test]
551 fn checked_mul_normal() {
552 let half = D38s12::from_bits(500_000_000_000);
553 let quarter = D38s12::from_bits(250_000_000_000);
554 assert_eq!(half.checked_mul(half), Some(quarter));
555 }
556
557 #[test]
558 fn checked_mul_zero() {
559 assert_eq!(D38s12::MAX.checked_mul(D38s12::ZERO), Some(D38s12::ZERO));
560 assert_eq!(D38s12::ZERO.checked_mul(D38s12::ZERO), Some(D38s12::ZERO));
561 }
562
563 #[test]
564 fn checked_mul_one_identity() {
565 let v = D38s12::from_bits(7_500_000_000_000); assert_eq!(v.checked_mul(D38s12::ONE), Some(v));
567 assert_eq!(D38s12::ONE.checked_mul(v), Some(v));
568 }
569
570 #[test]
571 fn checked_mul_overflow_returns_none() {
572 assert_eq!(D38s12::MAX.checked_mul(two()), None);
574 }
575
576 #[test]
577 fn checked_mul_min_overflow_returns_none() {
578 assert_eq!(D38s12::MIN.checked_mul(two()), None);
580 }
581
582 #[test]
583 fn wrapping_mul_normal() {
584 let half = D38s12::from_bits(500_000_000_000);
585 let quarter = D38s12::from_bits(250_000_000_000);
586 assert_eq!(half.wrapping_mul(half), quarter);
587 }
588
589 #[test]
590 fn wrapping_mul_overflow_does_not_panic() {
591 let _ = D38s12::MAX.wrapping_mul(two());
593 let _ = D38s12::MIN.wrapping_mul(two());
594 }
595
596 #[test]
597 fn saturating_mul_normal() {
598 let half = D38s12::from_bits(500_000_000_000);
599 let quarter = D38s12::from_bits(250_000_000_000);
600 assert_eq!(half.saturating_mul(half), quarter);
601 }
602
603 #[test]
604 fn saturating_mul_positive_overflow_clamps_to_max() {
605 assert_eq!(D38s12::MAX.saturating_mul(two()), D38s12::MAX);
607 }
608
609 #[test]
610 fn saturating_mul_negative_overflow_clamps_to_min() {
611 assert_eq!(
613 D38s12::MAX.saturating_mul(-two()),
614 D38s12::MIN
615 );
616 }
617
618 #[test]
619 fn saturating_mul_min_times_two_clamps_to_min() {
620 assert_eq!(D38s12::MIN.saturating_mul(two()), D38s12::MIN);
622 }
623
624 #[test]
625 fn saturating_mul_min_times_neg_two_clamps_to_max() {
626 assert_eq!(D38s12::MIN.saturating_mul(-two()), D38s12::MAX);
628 }
629
630 #[test]
631 fn overflowing_mul_normal_no_overflow() {
632 let half = D38s12::from_bits(500_000_000_000);
633 let quarter = D38s12::from_bits(250_000_000_000);
634 assert_eq!(half.overflowing_mul(half), (quarter, false));
635 }
636
637 #[test]
638 fn overflowing_mul_overflow_flagged() {
639 let (_, ovf) = D38s12::MAX.overflowing_mul(two());
640 assert!(ovf);
641 }
642
643 #[test]
646 fn checked_div_normal() {
647 let six = D38s12::from_bits(6_000_000_000_000);
649 assert_eq!(six.checked_div(two()), Some(three()));
650 }
651
652 #[test]
653 fn checked_div_by_zero_returns_none() {
654 assert_eq!(D38s12::ONE.checked_div(D38s12::ZERO), None);
655 }
656
657 #[test]
658 fn checked_div_overflow_returns_none() {
659 let half = D38s12::from_bits(500_000_000_000);
661 assert_eq!(D38s12::MAX.checked_div(half), None);
662 }
663
664 #[test]
665 fn checked_div_negative_normal() {
666 let neg_six = D38s12::from_bits(-6_000_000_000_000);
667 assert_eq!(neg_six.checked_div(two()), Some(-three()));
668 }
669
670 #[test]
671 fn wrapping_div_normal() {
672 let six = D38s12::from_bits(6_000_000_000_000);
673 assert_eq!(six.wrapping_div(two()), three());
674 }
675
676 #[test]
677 #[should_panic(expected = "attempt to divide by zero")]
678 fn wrapping_div_by_zero_panics() {
679 let _ = D38s12::ONE.wrapping_div(D38s12::ZERO);
680 }
681
682 #[test]
683 fn wrapping_div_overflow_does_not_panic() {
684 let half = D38s12::from_bits(500_000_000_000);
686 let _ = D38s12::MAX.wrapping_div(half);
687 }
688
689 #[test]
690 fn saturating_div_normal() {
691 let six = D38s12::from_bits(6_000_000_000_000);
692 assert_eq!(six.saturating_div(two()), three());
693 }
694
695 #[test]
696 #[should_panic(expected = "attempt to divide by zero")]
697 fn saturating_div_by_zero_panics() {
698 let _ = D38s12::ONE.saturating_div(D38s12::ZERO);
699 }
700
701 #[test]
702 fn saturating_div_overflow_clamps_to_max() {
703 let half = D38s12::from_bits(500_000_000_000);
705 assert_eq!(D38s12::MAX.saturating_div(half), D38s12::MAX);
706 }
707
708 #[test]
709 fn saturating_div_negative_overflow_clamps_to_min() {
710 let neg_half = D38s12::from_bits(-500_000_000_000);
712 assert_eq!(
713 D38s12::MAX.saturating_div(neg_half),
714 D38s12::MIN
715 );
716 }
717
718 #[test]
719 fn overflowing_div_normal() {
720 let six = D38s12::from_bits(6_000_000_000_000);
721 assert_eq!(six.overflowing_div(two()), (three(), false));
722 }
723
724 #[test]
725 fn overflowing_div_overflow_flagged() {
726 let half = D38s12::from_bits(500_000_000_000);
727 let (_, ovf) = D38s12::MAX.overflowing_div(half);
728 assert!(ovf);
729 }
730
731 #[test]
732 #[should_panic(expected = "attempt to divide by zero")]
733 fn overflowing_div_by_zero_panics() {
734 let _ = D38s12::ONE.overflowing_div(D38s12::ZERO);
735 }
736
737 #[test]
740 fn checked_rem_normal() {
741 let a = D38s12::from_bits(5_500_000_000_000);
743 let expected = D38s12::from_bits(1_500_000_000_000);
744 assert_eq!(a.checked_rem(two()), Some(expected));
745 }
746
747 #[test]
748 fn checked_rem_by_zero_returns_none() {
749 assert_eq!(D38s12::ONE.checked_rem(D38s12::ZERO), None);
750 }
751
752 #[test]
753 fn checked_rem_min_neg_one_lsb_returns_none() {
754 let neg_one_lsb = D38s12::from_bits(-1);
758 assert_eq!(D38s12::MIN.checked_rem(neg_one_lsb), None);
759 }
760
761 #[test]
762 fn wrapping_rem_normal() {
763 let a = D38s12::from_bits(5_500_000_000_000);
764 let expected = D38s12::from_bits(1_500_000_000_000);
765 assert_eq!(a.wrapping_rem(two()), expected);
766 }
767
768 #[test]
769 #[should_panic(expected = "attempt to calculate the remainder with a divisor of zero")]
770 fn wrapping_rem_by_zero_panics() {
771 let _ = D38s12::ONE.wrapping_rem(D38s12::ZERO);
772 }
773
774 #[test]
775 fn wrapping_rem_min_neg_one_lsb_returns_zero() {
776 let neg_one_lsb = D38s12::from_bits(-1);
778 assert_eq!(
779 D38s12::MIN.wrapping_rem(neg_one_lsb),
780 D38s12::ZERO
781 );
782 }
783
784 #[test]
785 fn overflowing_rem_normal() {
786 let a = D38s12::from_bits(5_500_000_000_000);
787 let expected = D38s12::from_bits(1_500_000_000_000);
788 assert_eq!(a.overflowing_rem(two()), (expected, false));
789 }
790
791 #[test]
792 fn overflowing_rem_min_neg_one_lsb_flagged() {
793 let neg_one_lsb = D38s12::from_bits(-1);
794 assert_eq!(
795 D38s12::MIN.overflowing_rem(neg_one_lsb),
796 (D38s12::ZERO, true)
797 );
798 }
799
800 #[test]
804 fn variants_at_scale_6() {
805 type D6 = D38<6>;
806 let one = D6::ONE;
807 let two_d6 = D6::from_bits(2_000_000); let one_lsb = D6::from_bits(1);
809
810 assert_eq!(one.checked_add(one), Some(two_d6));
811 assert_eq!(D6::MAX.checked_add(one_lsb), None);
813 assert_eq!(D6::MAX.saturating_add(one_lsb), D6::MAX);
814 assert_eq!(D6::MAX.wrapping_add(one_lsb), D6::MIN);
815 assert_eq!(
816 D6::MAX.overflowing_add(one_lsb),
817 (D6::MIN, true)
818 );
819
820 assert_eq!(D6::MIN.checked_neg(), None);
821 assert_eq!(D6::MIN.wrapping_neg(), D6::MIN);
822 assert_eq!(D6::MIN.saturating_neg(), D6::MAX);
823 }
824
825 #[test]
827 fn checked_matches_op_in_range() {
828 let a = D38s12::from_bits(7_500_000_000_000); let b = two();
830 assert_eq!(a.checked_add(b), Some(a + b));
831 assert_eq!(a.checked_sub(b), Some(a - b));
832 assert_eq!(a.checked_mul(b), Some(a * b));
833 assert_eq!(a.checked_div(b), Some(a / b));
834 assert_eq!(a.checked_rem(b), Some(a % b));
835 }
836
837 #[test]
839 fn overflowing_flag_matches_checked_none() {
840 let (_, ovf) = D38s12::MAX.overflowing_add(D38s12::ONE);
842 assert_eq!(ovf, D38s12::MAX.checked_add(D38s12::ONE).is_none());
843
844 let (_, ovf) = D38s12::MIN.overflowing_sub(D38s12::ONE);
846 assert_eq!(ovf, D38s12::MIN.checked_sub(D38s12::ONE).is_none());
847
848 let (_, ovf) = D38s12::MAX.overflowing_mul(two());
850 assert_eq!(ovf, D38s12::MAX.checked_mul(two()).is_none());
851
852 let (_, ovf) = D38s12::MIN.overflowing_neg();
854 assert_eq!(ovf, D38s12::MIN.checked_neg().is_none());
855
856 let neg_one_lsb = D38s12::from_bits(-1);
858 let (_, ovf) = D38s12::MIN.overflowing_rem(neg_one_lsb);
859 assert_eq!(
860 ovf,
861 D38s12::MIN.checked_rem(neg_one_lsb).is_none()
862 );
863 }
864
865 #[test]
868 fn saturating_never_escapes_bounds() {
869 let extremes = [
870 D38s12::MIN,
871 D38s12::from_bits(-1),
872 D38s12::ZERO,
873 D38s12::ONE,
874 D38s12::MAX,
875 ];
876 for &a in &extremes {
877 for &b in &extremes {
878 let s_add = a.saturating_add(b);
879 let s_sub = a.saturating_sub(b);
880 let s_mul = a.saturating_mul(b);
881 assert!(s_add >= D38s12::MIN && s_add <= D38s12::MAX);
882 assert!(s_sub >= D38s12::MIN && s_sub <= D38s12::MAX);
883 assert!(s_mul >= D38s12::MIN && s_mul <= D38s12::MAX);
884 }
885 }
886 }
887}