1use core::ops::{Div, DivAssign, Mul, MulAssign};
37
38use crate::core_type::D38;
39
40impl<const SCALE: u32> Mul for D38<SCALE> {
41 type Output = Self;
42
43 #[inline]
71 fn mul(self, rhs: Self) -> Self {
72 match crate::mg_divide::mul_div_pow10::<SCALE>(self.0, rhs.0) {
73 Some(q) => Self(q),
74 None => Self(panic_or_wrap_mul::<SCALE>(self.0, rhs.0)),
75 }
76 }
77}
78
79impl<const SCALE: u32> MulAssign for D38<SCALE> {
80 #[inline]
86 fn mul_assign(&mut self, rhs: Self) {
87 *self = *self * rhs;
88 }
89}
90
91impl<const SCALE: u32> Div for D38<SCALE> {
92 type Output = Self;
93
94 #[inline]
122 fn div(self, rhs: Self) -> Self {
123 assert!(rhs.0 != 0, "attempt to divide by zero");
125 match crate::mg_divide::div_pow10_div::<SCALE>(self.0, rhs.0) {
126 Some(q) => Self(q),
127 None => Self(panic_or_wrap_div::<SCALE>(self.0, rhs.0)),
128 }
129 }
130}
131
132impl<const SCALE: u32> DivAssign for D38<SCALE> {
133 #[inline]
139 fn div_assign(&mut self, rhs: Self) {
140 *self = *self / rhs;
141 }
142}
143
144impl<const SCALE: u32> D38<SCALE> {
145 #[inline]
164 #[must_use]
165 pub fn mul_with(self, rhs: Self, mode: crate::rounding::RoundingMode) -> Self {
166 match crate::mg_divide::mul_div_pow10_with::<SCALE>(self.0, rhs.0, mode) {
167 Some(q) => Self(q),
168 None => Self(panic_or_wrap_mul::<SCALE>(self.0, rhs.0)),
169 }
170 }
171
172 #[inline]
188 #[must_use]
189 pub fn div_with(self, rhs: Self, mode: crate::rounding::RoundingMode) -> Self {
190 assert!(rhs.0 != 0, "attempt to divide by zero");
191 match crate::mg_divide::div_pow10_div_with::<SCALE>(self.0, rhs.0, mode) {
192 Some(q) => Self(q),
193 None => Self(panic_or_wrap_div::<SCALE>(self.0, rhs.0)),
194 }
195 }
196}
197
198#[inline(always)]
213#[allow(clippy::arithmetic_side_effects)]
214fn panic_or_wrap_mul<const SCALE: u32>(a: i128, b: i128) -> i128 {
215 #[cfg(debug_assertions)]
216 {
217 let _ = (a, b);
218 panic!("attempt to multiply with overflow");
219 }
220 #[cfg(not(debug_assertions))]
221 {
222 a.wrapping_mul(b).wrapping_div(D38::<SCALE>::multiplier())
223 }
224}
225
226#[inline(always)]
232#[allow(clippy::arithmetic_side_effects)]
233fn panic_or_wrap_div<const SCALE: u32>(a: i128, b: i128) -> i128 {
234 #[cfg(debug_assertions)]
235 {
236 let _ = (a, b);
237 panic!("attempt to divide with overflow");
238 }
239 #[cfg(not(debug_assertions))]
240 {
241 a.wrapping_mul(D38::<SCALE>::multiplier()).wrapping_div(b)
242 }
243}
244
245#[cfg(test)]
246mod tests {
247 use crate::core_type::D38s12;
248
249 #[test]
251 fn add_zero_to_zero_is_zero() {
252 assert_eq!(D38s12::ZERO + D38s12::ZERO, D38s12::ZERO);
253 }
254
255 #[test]
257 fn sub_zero_from_zero_is_zero() {
258 assert_eq!(D38s12::ZERO - D38s12::ZERO, D38s12::ZERO);
259 }
260
261 #[test]
263 fn neg_zero_is_zero() {
264 assert_eq!(-D38s12::ZERO, D38s12::ZERO);
265 }
266
267 #[test]
269 fn add_assign_zero() {
270 let mut v = D38s12::ZERO;
271 v += D38s12::ZERO;
272 assert_eq!(v, D38s12::ZERO);
273 }
274
275 #[test]
277 fn sub_assign_zero() {
278 let mut v = D38s12::ZERO;
279 v -= D38s12::ZERO;
280 assert_eq!(v, D38s12::ZERO);
281 }
282
283 #[test]
287 fn add_sub_round_trip_canonical_claim() {
288 let a = D38s12::from_bits(1_500_000_000_000);
289 let b = D38s12::from_bits(250_000_000_000);
290 assert_eq!((a + b) - b, a);
291 }
292
293 #[test]
295 fn add_sub_round_trip_negative() {
296 let a = D38s12::from_bits(-7_321_654_987_000);
297 let b = D38s12::from_bits(42_000_000_000_000);
298 assert_eq!((a + b) - b, a);
299 }
300
301 #[test]
303 fn one_plus_one_is_two_in_scaled_bits() {
304 let two = D38s12::ONE + D38s12::ONE;
305 assert_eq!(two.to_bits(), 2_000_000_000_000);
307 }
308
309 #[test]
311 fn neg_one_plus_one_is_zero() {
312 assert_eq!(-D38s12::ONE + D38s12::ONE, D38s12::ZERO);
313 }
314
315 #[test]
321 #[cfg(debug_assertions)]
322 #[should_panic(expected = "overflow")]
323 fn add_overflow_panics_in_debug() {
324 let _ = D38s12::MAX + D38s12::ONE;
325 }
326
327 #[test]
329 #[cfg(debug_assertions)]
330 #[should_panic(expected = "overflow")]
331 fn sub_underflow_panics_in_debug() {
332 let _ = D38s12::MIN - D38s12::ONE;
333 }
334
335 #[test]
338 #[cfg(debug_assertions)]
339 #[should_panic(expected = "overflow")]
340 fn neg_min_panics_in_debug() {
341 let _ = -D38s12::MIN;
342 }
343
344 #[test]
346 fn add_assign_accumulates() {
347 let mut v = D38s12::from_bits(100);
348 v += D38s12::from_bits(250);
349 assert_eq!(v.to_bits(), 350);
350 v += D38s12::from_bits(-50);
351 assert_eq!(v.to_bits(), 300);
352 }
353
354 #[test]
356 fn sub_assign_accumulates() {
357 let mut v = D38s12::from_bits(1000);
358 v -= D38s12::from_bits(250);
359 assert_eq!(v.to_bits(), 750);
360 }
361
362 #[test]
366 fn mul_one_one_is_one() {
367 assert_eq!(D38s12::ONE * D38s12::ONE, D38s12::ONE);
368 }
369
370 #[test]
372 fn div_one_one_is_one() {
373 assert_eq!(D38s12::ONE / D38s12::ONE, D38s12::ONE);
374 }
375
376 #[test]
378 fn rem_zero_one_is_zero() {
379 assert_eq!(D38s12::ZERO % D38s12::ONE, D38s12::ZERO);
380 }
381
382 #[test]
384 fn mul_zero_is_zero() {
385 let x = D38s12::from_bits(1_500_000_000_000); assert_eq!(D38s12::ZERO * x, D38s12::ZERO);
387 assert_eq!(x * D38s12::ZERO, D38s12::ZERO);
388 }
389
390 #[test]
392 fn mul_one_is_identity() {
393 let x = D38s12::from_bits(1_500_000_000_000); assert_eq!(D38s12::ONE * x, x);
395 assert_eq!(x * D38s12::ONE, x);
396
397 let y = D38s12::from_bits(-7_321_654_987_000); assert_eq!(D38s12::ONE * y, y);
399 assert_eq!(y * D38s12::ONE, y);
400 }
401
402 #[test]
404 fn div_one_is_identity() {
405 let x = D38s12::from_bits(1_500_000_000_000);
406 assert_eq!(x / D38s12::ONE, x);
407
408 let y = D38s12::from_bits(-7_321_654_987_000);
409 assert_eq!(y / D38s12::ONE, y);
410 }
411
412 #[test]
414 fn div_self_is_one() {
415 let x = D38s12::from_bits(1_500_000_000_000); assert_eq!(x / x, D38s12::ONE);
417
418 let y = D38s12::from_bits(-7_321_654_987_000);
419 assert_eq!(y / y, D38s12::ONE);
420
421 let small = D38s12::from_bits(1); assert_eq!(small / small, D38s12::ONE);
425 }
426
427 #[test]
429 fn rem_multiple_is_zero() {
430 let x = D38s12::from_bits(3_500_000_000_000); let seven = D38s12::ONE + D38s12::ONE + D38s12::ONE + D38s12::ONE
432 + D38s12::ONE + D38s12::ONE + D38s12::ONE; assert_eq!((x * seven) % x, D38s12::ZERO);
434 }
435
436 #[test]
438 fn rem_self_is_zero() {
439 let x = D38s12::from_bits(1_500_000_000_000);
440 assert_eq!(x % x, D38s12::ZERO);
441
442 let y = D38s12::from_bits(-7_321_654_987_000);
443 assert_eq!(y % y, D38s12::ZERO);
444 }
445
446 #[test]
451 fn one_point_one_plus_two_point_two_equals_three_point_three() {
452 let one_point_one = D38s12::from_bits(1_100_000_000_000); let two_point_two = D38s12::from_bits(2_200_000_000_000); let three_point_three = D38s12::from_bits(3_300_000_000_000); assert_eq!(one_point_one + two_point_two, three_point_three);
456 }
457
458 #[test]
462 fn mul_round_trip_canonical_claim() {
463 let a = D38s12::from_bits(1_500_000_000_000);
465 let b = D38s12::from_bits(2_500_000_000_000);
466 let product = a * b;
467 assert_eq!(product, D38s12::from_bits(3_750_000_000_000));
468 assert_eq!(product / b, a);
469
470 let c = D38s12::from_bits(-7_321_654_987_000);
472 let d = D38s12::from_bits(13_000_000_000); let cd = c * d;
474 assert_eq!(cd / d, c);
475 }
476
477 #[test]
479 fn mul_assign_matches_mul() {
480 let a = D38s12::from_bits(1_500_000_000_000);
481 let b = D38s12::from_bits(2_500_000_000_000);
482 let mut x = a;
483 x *= b;
484 assert_eq!(x, a * b);
485 }
486
487 #[test]
489 fn div_assign_matches_div() {
490 let a = D38s12::from_bits(3_750_000_000_000);
491 let b = D38s12::from_bits(2_500_000_000_000);
492 let mut x = a;
493 x /= b;
494 assert_eq!(x, a / b);
495 }
496
497 #[test]
499 fn rem_assign_matches_rem() {
500 let a = D38s12::from_bits(7_500_000_000_000);
501 let b = D38s12::from_bits(2_000_000_000_000); let mut x = a;
503 x %= b;
504 assert_eq!(x, a % b);
505 }
506
507 #[test]
509 fn mul_is_commutative() {
510 let a = D38s12::from_bits(1_500_000_000_000);
511 let b = D38s12::from_bits(2_500_000_000_000);
512 assert_eq!(a * b, b * a);
513 }
514
515 #[test]
517 fn mul_subunit_rescales_exactly() {
518 let half = D38s12::from_bits(500_000_000_000); let quarter = D38s12::from_bits(250_000_000_000); assert_eq!(half * half, quarter);
521 }
522
523 #[test]
525 fn div_rescales_exactly() {
526 let half = D38s12::from_bits(500_000_000_000); let two = D38s12::from_bits(2_000_000_000_000); let quarter = D38s12::from_bits(250_000_000_000); assert_eq!(half / two, quarter);
530 }
531
532 #[test]
535 fn rem_truncates_toward_zero() {
536 let a = D38s12::from_bits(5_500_000_000_000);
537 let b = D38s12::from_bits(2_000_000_000_000);
538 let expected = D38s12::from_bits(1_500_000_000_000);
539 assert_eq!(a % b, expected);
540
541 let neg = D38s12::from_bits(-5_500_000_000_000);
543 let neg_expected = D38s12::from_bits(-1_500_000_000_000);
544 assert_eq!(neg % b, neg_expected);
545 }
546
547 #[test]
551 #[cfg(debug_assertions)]
552 #[should_panic(expected = "overflow")]
553 fn mul_overflow_panics_in_debug() {
554 let two = D38s12::from_bits(2_000_000_000_000);
555 let _ = D38s12::MAX * two;
556 }
557
558 #[test]
566 fn mul_wide_operands_match_widened_form() {
567 let a = D38s12::from_bits(50_000_000_000_000_000_000_000);
568 let b = D38s12::from_bits(30_000_000_000_000_000_000_000);
569 let expected = D38s12::from_bits(1_500_000_000_000_000_000_000_000_000_000_000);
570 assert_eq!(a * b, expected);
571 assert_eq!(b * a, expected);
573 }
574
575 #[test]
577 fn mul_div_wide_round_trip() {
578 let a = D38s12::from_bits(50_000_000_000_000_000_000_000);
579 let b = D38s12::from_bits(30_000_000_000_000_000_000_000);
580 let prod = a * b;
581 assert_eq!(prod / b, a);
583 }
584
585 #[test]
587 fn mul_wide_negative_signs() {
588 let a = D38s12::from_bits(50_000_000_000_000_000_000_000);
589 let b = D38s12::from_bits(30_000_000_000_000_000_000_000);
590 let neg_a = -a;
591 let neg_b = -b;
592 let pos_prod = a * b;
593 let neg_prod = -pos_prod;
594 assert_eq!(neg_a * b, neg_prod);
595 assert_eq!(a * neg_b, neg_prod);
596 assert_eq!(neg_a * neg_b, pos_prod);
597 }
598
599 #[test]
601 fn div_wide_dividend_correct() {
602 let a = D38s12::from_bits(10_i128.pow(22));
604 let b = D38s12::from_bits(2);
606 let expected = D38s12::from_bits(5 * 10_i128.pow(33));
608 assert_eq!(a / b, expected);
609 }
610
611 #[test]
614 fn div_wide_round_trip_exact() {
615 let a = D38s12::from_bits(10_i128.pow(27));
618 let b = D38s12::from_bits(100);
619 let q = a / b;
620 let expected = D38s12::from_bits(10_i128.pow(37));
622 assert_eq!(q, expected);
623 }
624
625 #[test]
628 fn div_scale_zero_matches_i128_div() {
629 if !crate::rounding::DEFAULT_IS_HALF_TO_EVEN {
630 return;
631 }
632 type D0 = crate::core_type::D38<0>;
633 let a = D0::from_bits(15);
634 let b = D0::from_bits(4);
635 assert_eq!(a / b, D0::from_bits(4));
637 assert_eq!((-a) / b, D0::from_bits(-4));
638 let c = D0::from_bits(16);
640 assert_eq!(c / b, D0::from_bits(4));
641 }
642
643 #[test]
645 fn mul_scale_zero_matches_i128_mul() {
646 type D0 = crate::core_type::D38<0>;
647 let a = D0::from_bits(7);
648 let b = D0::from_bits(11);
649 assert_eq!(a * b, D0::from_bits(77));
650 assert_eq!((-a) * b, D0::from_bits(-77));
651 }
652
653 #[test]
655 #[should_panic]
656 fn div_by_zero_panics() {
657 let _ = D38s12::ONE / D38s12::ZERO;
658 }
659
660 #[test]
662 #[should_panic]
663 fn rem_by_zero_panics() {
664 let _ = D38s12::ONE % D38s12::ZERO;
665 }
666
667 #[test]
673 fn abs_zero_is_zero() {
674 assert_eq!(D38s12::ZERO.abs(), D38s12::ZERO);
675 }
676
677 #[test]
679 fn abs_positive_is_self() {
680 let x = D38s12::from_bits(1_500_000_000_000); assert_eq!(x.abs(), x);
682 }
683
684 #[test]
686 fn abs_negative_is_positive() {
687 let neg = D38s12::from_bits(-1_500_000_000_000);
688 let pos = D38s12::from_bits(1_500_000_000_000);
689 assert_eq!(neg.abs(), pos);
690 }
691
692 #[test]
695 #[cfg(debug_assertions)]
696 #[should_panic(expected = "overflow")]
697 fn abs_min_panics_in_debug() {
698 let _ = D38s12::MIN.abs();
699 }
700
701 #[test]
705 fn signum_zero_is_zero() {
706 assert_eq!(D38s12::ZERO.signum(), D38s12::ZERO);
707 }
708
709 #[test]
711 fn signum_positive_is_one() {
712 let x = D38s12::from_bits(1_500_000_000_000);
713 assert_eq!(x.signum(), D38s12::ONE);
714
715 let tiny = D38s12::from_bits(1);
717 assert_eq!(tiny.signum(), D38s12::ONE);
718 }
719
720 #[test]
722 fn signum_negative_is_neg_one() {
723 let x = D38s12::from_bits(-1_500_000_000_000);
724 assert_eq!(x.signum(), -D38s12::ONE);
725
726 let tiny_neg = D38s12::from_bits(-1);
727 assert_eq!(tiny_neg.signum(), -D38s12::ONE);
728 }
729
730 #[test]
734 fn floor_positive_fractional_rounds_down() {
735 let x = D38s12::from_bits(2_500_000_000_000);
736 let expected = D38s12::from_bits(2_000_000_000_000);
737 assert_eq!(x.floor(), expected);
738 }
739
740 #[test]
744 fn floor_negative_fractional_rounds_down_toward_neg_inf() {
745 let x = D38s12::from_bits(-2_500_000_000_000);
746 let expected = D38s12::from_bits(-3_000_000_000_000);
747 assert_eq!(x.floor(), expected);
748
749 let small_neg = D38s12::from_bits(-500_000_000_000);
751 let small_expected = D38s12::from_bits(-1_000_000_000_000);
752 assert_eq!(small_neg.floor(), small_expected);
753 }
754
755 #[test]
757 fn floor_integer_unchanged() {
758 let two = D38s12::from_bits(2_000_000_000_000);
759 assert_eq!(two.floor(), two);
760
761 let neg_two = D38s12::from_bits(-2_000_000_000_000);
762 assert_eq!(neg_two.floor(), neg_two);
763
764 assert_eq!(D38s12::ZERO.floor(), D38s12::ZERO);
765 }
766
767 #[test]
771 fn ceil_positive_fractional_rounds_up() {
772 let x = D38s12::from_bits(2_500_000_000_000);
773 let expected = D38s12::from_bits(3_000_000_000_000);
774 assert_eq!(x.ceil(), expected);
775 }
776
777 #[test]
780 fn ceil_negative_fractional_rounds_up_toward_pos_inf() {
781 let x = D38s12::from_bits(-2_500_000_000_000);
782 let expected = D38s12::from_bits(-2_000_000_000_000);
783 assert_eq!(x.ceil(), expected);
784
785 let small_neg = D38s12::from_bits(-500_000_000_000);
787 assert_eq!(small_neg.ceil(), D38s12::ZERO);
788 }
789
790 #[test]
792 fn ceil_integer_unchanged() {
793 let two = D38s12::from_bits(2_000_000_000_000);
794 assert_eq!(two.ceil(), two);
795
796 let neg_two = D38s12::from_bits(-2_000_000_000_000);
797 assert_eq!(neg_two.ceil(), neg_two);
798
799 assert_eq!(D38s12::ZERO.ceil(), D38s12::ZERO);
800 }
801
802 #[test]
812 fn round_half_away_from_zero() {
813 let two_point_five = D38s12::from_bits(2_500_000_000_000);
815 assert_eq!(two_point_five.round(), D38s12::from_bits(3_000_000_000_000));
816
817 let two_point_four = D38s12::from_bits(2_400_000_000_000);
818 assert_eq!(two_point_four.round(), D38s12::from_bits(2_000_000_000_000));
819
820 let two_point_six = D38s12::from_bits(2_600_000_000_000);
821 assert_eq!(two_point_six.round(), D38s12::from_bits(3_000_000_000_000));
822
823 let neg_two_point_five = D38s12::from_bits(-2_500_000_000_000);
825 assert_eq!(neg_two_point_five.round(), D38s12::from_bits(-3_000_000_000_000));
826
827 let neg_two_point_four = D38s12::from_bits(-2_400_000_000_000);
828 assert_eq!(neg_two_point_four.round(), D38s12::from_bits(-2_000_000_000_000));
829
830 let neg_two_point_six = D38s12::from_bits(-2_600_000_000_000);
831 assert_eq!(neg_two_point_six.round(), D38s12::from_bits(-3_000_000_000_000));
832
833 assert_eq!(D38s12::ZERO.round(), D38s12::ZERO);
835 }
836
837 #[test]
842 fn trunc_drops_fractional() {
843 let x = D38s12::from_bits(2_500_000_000_000);
845 assert_eq!(x.trunc(), D38s12::from_bits(2_000_000_000_000));
846
847 let neg = D38s12::from_bits(-2_500_000_000_000);
850 assert_eq!(neg.trunc(), D38s12::from_bits(-2_000_000_000_000));
851
852 assert_eq!(D38s12::ZERO.trunc(), D38s12::ZERO);
854
855 let two = D38s12::from_bits(2_000_000_000_000);
857 assert_eq!(two.trunc(), two);
858 }
859
860 #[test]
863 fn fract_keeps_only_fractional() {
864 let x = D38s12::from_bits(2_500_000_000_000);
865 assert_eq!(x.fract(), D38s12::from_bits(500_000_000_000));
866
867 let neg = D38s12::from_bits(-2_500_000_000_000);
869 assert_eq!(neg.fract(), D38s12::from_bits(-500_000_000_000));
870
871 let two = D38s12::from_bits(2_000_000_000_000);
873 assert_eq!(two.fract(), D38s12::ZERO);
874
875 assert_eq!(D38s12::ZERO.fract(), D38s12::ZERO);
876 }
877
878 #[test]
880 fn trunc_plus_fract_equals_self() {
881 let cases = [
882 D38s12::from_bits(2_500_000_000_000),
883 D38s12::from_bits(-2_500_000_000_000),
884 D38s12::from_bits(7_321_654_987_000),
885 D38s12::from_bits(-7_321_654_987_000),
886 D38s12::ZERO,
887 D38s12::ONE,
888 -D38s12::ONE,
889 D38s12::from_bits(1), D38s12::from_bits(-1),
891 ];
892 for x in cases {
893 assert_eq!(x.trunc() + x.fract(), x, "failed for {:?}", x);
894 }
895 }
896
897 #[test]
901 fn min_max_clamp_basic() {
902 let a = D38s12::from_bits(1_000_000_000_000); let b = D38s12::from_bits(2_000_000_000_000); let c = D38s12::from_bits(3_000_000_000_000); assert_eq!(a.min(b), a);
907 assert_eq!(b.min(a), a);
908 assert_eq!(a.max(b), b);
909 assert_eq!(b.max(a), b);
910
911 assert_eq!(b.clamp(a, c), b);
913 assert_eq!(D38s12::ZERO.clamp(a, c), a);
915 let four = D38s12::from_bits(4_000_000_000_000);
917 assert_eq!(four.clamp(a, c), c);
918
919 let neg_a = -a;
921 let neg_b = -b;
922 assert_eq!(neg_a.min(neg_b), neg_b); assert_eq!(neg_a.max(neg_b), neg_a);
924 }
925
926 #[test]
930 fn recip_inverts_known_values() {
931 let two = D38s12::from_bits(2_000_000_000_000);
932 let half = D38s12::from_bits(500_000_000_000);
933 assert_eq!(two.recip(), half);
934 assert_eq!(half.recip(), two);
935
936 assert_eq!(D38s12::ONE.recip(), D38s12::ONE);
938
939 assert_eq!((-D38s12::ONE).recip(), -D38s12::ONE);
941 }
942
943 #[test]
945 #[should_panic]
946 fn recip_zero_panics() {
947 let _ = D38s12::ZERO.recip();
948 }
949
950 #[test]
954 fn copysign_basic() {
955 let pos = D38s12::from_bits(1_500_000_000_000);
956 let neg = D38s12::from_bits(-1_500_000_000_000);
957
958 assert_eq!(pos.copysign(pos), pos);
960 assert_eq!(pos.copysign(neg), neg);
962 assert_eq!(neg.copysign(pos), pos);
964 assert_eq!(neg.copysign(neg), neg);
966 }
967
968 #[test]
971 fn copysign_zero() {
972 let neg = D38s12::from_bits(-1_500_000_000_000);
973 let pos = D38s12::from_bits(1_500_000_000_000);
974
975 assert_eq!(neg.copysign(D38s12::ZERO), pos);
977 assert_eq!(pos.copysign(D38s12::ZERO), pos);
978
979 assert_eq!(D38s12::ZERO.copysign(neg), D38s12::ZERO);
981 assert_eq!(D38s12::ZERO.copysign(pos), D38s12::ZERO);
982 }
983
984 #[test]
989 fn div_euclid_positive() {
990 let a = D38s12::from_bits(5_000_000_000_000); let b = D38s12::from_bits(2_000_000_000_000); let q = a.div_euclid(b);
994 assert_eq!(q, D38s12::from_bits(2_000_000_000_000)); let r = a.rem_euclid(b);
997 assert_eq!(r, D38s12::from_bits(1_000_000_000_000)); assert_eq!(q * b + r, a);
1001 }
1002
1003 #[test]
1006 fn div_euclid_negative_dividend() {
1007 let a = D38s12::from_bits(-5_000_000_000_000); let b = D38s12::from_bits(2_000_000_000_000); let q = a.div_euclid(b);
1011 assert_eq!(q, D38s12::from_bits(-3_000_000_000_000));
1013
1014 let r = a.rem_euclid(b);
1015 assert_eq!(r, D38s12::from_bits(1_000_000_000_000));
1016
1017 assert_eq!(q * b + r, a);
1019 }
1020
1021 #[test]
1024 fn div_euclid_negative_divisor() {
1025 let a = D38s12::from_bits(5_000_000_000_000); let b = D38s12::from_bits(-2_000_000_000_000); let q = a.div_euclid(b);
1029 assert_eq!(q, D38s12::from_bits(-2_000_000_000_000)); let r = a.rem_euclid(b);
1032 assert_eq!(r, D38s12::from_bits(1_000_000_000_000)); assert_eq!(q * b + r, a);
1036 }
1037
1038 #[test]
1041 fn rem_euclid_consistency_with_div_euclid() {
1042 let cases: &[(i128, i128)] = &[
1043 (5_000_000_000_000, 2_000_000_000_000),
1044 (-5_000_000_000_000, 2_000_000_000_000),
1045 (5_000_000_000_000, -2_000_000_000_000),
1046 (-5_000_000_000_000, -2_000_000_000_000),
1047 (7_321_654_987_000, 13_000_000_000),
1048 (-7_321_654_987_000, 13_000_000_000),
1049 ];
1050 for (a_bits, b_bits) in cases {
1051 let a = D38s12::from_bits(*a_bits);
1052 let b = D38s12::from_bits(*b_bits);
1053 let q = a.div_euclid(b);
1054 let r = a.rem_euclid(b);
1055 assert_eq!(q * b + r, a, "failed for a={}, b={}", a_bits, b_bits);
1056 assert!(r.0 >= 0, "rem_euclid returned negative for a={}, b={}: {}",
1058 a_bits, b_bits, r.0);
1059 }
1060 }
1061
1062 #[test]
1067 fn div_floor_basic() {
1068 let a = D38s12::from_bits(5_000_000_000_000);
1070 let b = D38s12::from_bits(2_000_000_000_000);
1071 assert_eq!(a.div_floor(b), D38s12::from_bits(2_000_000_000_000));
1072
1073 let neg_a = D38s12::from_bits(-5_000_000_000_000);
1075 assert_eq!(neg_a.div_floor(b), D38s12::from_bits(-3_000_000_000_000));
1076
1077 let neg_b = D38s12::from_bits(-2_000_000_000_000);
1079 assert_eq!(neg_a.div_floor(neg_b), D38s12::from_bits(2_000_000_000_000));
1080
1081 assert_eq!(a.div_floor(neg_b), D38s12::from_bits(-3_000_000_000_000));
1084 }
1085
1086 #[test]
1088 fn div_ceil_basic() {
1089 let a = D38s12::from_bits(5_000_000_000_000);
1091 let b = D38s12::from_bits(2_000_000_000_000);
1092 assert_eq!(a.div_ceil(b), D38s12::from_bits(3_000_000_000_000));
1093
1094 let neg_a = D38s12::from_bits(-5_000_000_000_000);
1096 assert_eq!(neg_a.div_ceil(b), D38s12::from_bits(-2_000_000_000_000));
1097
1098 let four = D38s12::from_bits(4_000_000_000_000);
1100 assert_eq!(four.div_ceil(b), D38s12::from_bits(2_000_000_000_000));
1101 }
1102
1103 #[test]
1107 fn abs_diff_commutative() {
1108 let a = D38s12::from_bits(5_000_000_000_000); let b = D38s12::from_bits(2_000_000_000_000); let expected = D38s12::from_bits(3_000_000_000_000); assert_eq!(a.abs_diff(b), expected);
1113 assert_eq!(b.abs_diff(a), expected);
1114
1115 let neg_a = -a;
1117 let neg_b = -b;
1118 assert_eq!(neg_a.abs_diff(neg_b), expected);
1120 assert_eq!(neg_b.abs_diff(neg_a), expected);
1121
1122 let seven = D38s12::from_bits(7_000_000_000_000);
1124 assert_eq!(a.abs_diff(neg_b), seven);
1125 assert_eq!(neg_b.abs_diff(a), seven);
1126 }
1127
1128 #[test]
1130 fn abs_diff_zero() {
1131 let x = D38s12::from_bits(1_500_000_000_000);
1132 assert_eq!(x.abs_diff(x), D38s12::ZERO);
1133 assert_eq!(x.abs_diff(D38s12::ZERO), x.abs());
1134
1135 let neg = -x;
1136 assert_eq!(neg.abs_diff(D38s12::ZERO), x);
1137 }
1138
1139 #[test]
1143 fn midpoint_basic() {
1144 let a = D38s12::from_bits(1_000_000_000_000); let b = D38s12::from_bits(3_000_000_000_000); assert_eq!(a.midpoint(b), D38s12::from_bits(2_000_000_000_000)); let neg_a = -a;
1150 let neg_b = -b;
1151 assert_eq!(neg_a.midpoint(neg_b), D38s12::from_bits(-2_000_000_000_000));
1152
1153 assert_eq!(neg_a.midpoint(a), D38s12::ZERO);
1155 }
1156
1157 #[test]
1160 fn midpoint_no_overflow_at_max() {
1161 assert_eq!(D38s12::MAX.midpoint(D38s12::MAX), D38s12::MAX);
1164 assert_eq!(D38s12::MIN.midpoint(D38s12::MIN), D38s12::MIN);
1165 let mid = D38s12::MIN.midpoint(D38s12::MAX);
1170 assert!(mid.0 == 0 || mid.0 == -1,
1171 "midpoint(MIN, MAX) should be 0 or -1, got {}", mid.0);
1172 }
1173
1174 #[test]
1177 fn is_nan_always_false() {
1178 assert!(!D38s12::ZERO.is_nan());
1179 assert!(!D38s12::ONE.is_nan());
1180 assert!(!D38s12::MAX.is_nan());
1181 assert!(!D38s12::MIN.is_nan());
1182 }
1183
1184 #[test]
1185 fn is_infinite_always_false() {
1186 assert!(!D38s12::ZERO.is_infinite());
1187 assert!(!D38s12::MAX.is_infinite());
1188 assert!(!D38s12::MIN.is_infinite());
1189 }
1190
1191 #[test]
1192 fn is_finite_always_true() {
1193 assert!(D38s12::ZERO.is_finite());
1194 assert!(D38s12::ONE.is_finite());
1195 assert!(D38s12::MAX.is_finite());
1196 assert!(D38s12::MIN.is_finite());
1197 }
1198
1199 #[test]
1200 fn is_normal_zero_is_false() {
1201 assert!(!D38s12::ZERO.is_normal());
1202 }
1203
1204 #[test]
1205 fn is_normal_nonzero_is_true() {
1206 assert!(D38s12::ONE.is_normal());
1207 assert!((-D38s12::ONE).is_normal());
1208 assert!(D38s12::from_bits(1).is_normal()); assert!(D38s12::from_bits(-1).is_normal()); assert!(D38s12::MAX.is_normal());
1211 assert!(D38s12::MIN.is_normal());
1212 }
1213
1214 #[test]
1217 fn is_zero_predicates() {
1218 assert!(D38s12::ZERO.is_zero());
1219 assert!(!D38s12::ZERO.is_positive());
1220 assert!(!D38s12::ZERO.is_negative());
1221
1222 assert!(!D38s12::from_bits(1).is_zero());
1223 assert!(D38s12::from_bits(1).is_positive());
1224 assert!(!D38s12::from_bits(1).is_negative());
1225
1226 assert!(!D38s12::from_bits(-1).is_zero());
1227 assert!(!D38s12::from_bits(-1).is_positive());
1228 assert!(D38s12::from_bits(-1).is_negative());
1229 }
1230}