use core::ops::{Div, DivAssign, Mul, MulAssign};
use crate::core_type::D38;
impl<const SCALE: u32> Mul for D38<SCALE> {
type Output = Self;
#[inline]
fn mul(self, rhs: Self) -> Self {
match crate::mg_divide::mul_div_pow10::<SCALE>(self.0, rhs.0) {
Some(q) => Self(q),
None => Self(panic_or_wrap_mul::<SCALE>(self.0, rhs.0)),
}
}
}
impl<const SCALE: u32> MulAssign for D38<SCALE> {
#[inline]
fn mul_assign(&mut self, rhs: Self) {
*self = *self * rhs;
}
}
impl<const SCALE: u32> Div for D38<SCALE> {
type Output = Self;
#[inline]
fn div(self, rhs: Self) -> Self {
assert!(rhs.0 != 0, "attempt to divide by zero");
match crate::mg_divide::div_pow10_div::<SCALE>(self.0, rhs.0) {
Some(q) => Self(q),
None => Self(panic_or_wrap_div::<SCALE>(self.0, rhs.0)),
}
}
}
impl<const SCALE: u32> DivAssign for D38<SCALE> {
#[inline]
fn div_assign(&mut self, rhs: Self) {
*self = *self / rhs;
}
}
impl<const SCALE: u32> D38<SCALE> {
#[inline]
#[must_use]
pub fn mul_with(self, rhs: Self, mode: crate::rounding::RoundingMode) -> Self {
match crate::mg_divide::mul_div_pow10_with::<SCALE>(self.0, rhs.0, mode) {
Some(q) => Self(q),
None => Self(panic_or_wrap_mul::<SCALE>(self.0, rhs.0)),
}
}
#[inline]
#[must_use]
pub fn div_with(self, rhs: Self, mode: crate::rounding::RoundingMode) -> Self {
assert!(rhs.0 != 0, "attempt to divide by zero");
match crate::mg_divide::div_pow10_div_with::<SCALE>(self.0, rhs.0, mode) {
Some(q) => Self(q),
None => Self(panic_or_wrap_div::<SCALE>(self.0, rhs.0)),
}
}
}
#[inline(always)]
#[allow(clippy::arithmetic_side_effects)]
fn panic_or_wrap_mul<const SCALE: u32>(a: i128, b: i128) -> i128 {
#[cfg(debug_assertions)]
{
let _ = (a, b);
panic!("attempt to multiply with overflow");
}
#[cfg(not(debug_assertions))]
{
a.wrapping_mul(b).wrapping_div(D38::<SCALE>::multiplier())
}
}
#[inline(always)]
#[allow(clippy::arithmetic_side_effects)]
fn panic_or_wrap_div<const SCALE: u32>(a: i128, b: i128) -> i128 {
#[cfg(debug_assertions)]
{
let _ = (a, b);
panic!("attempt to divide with overflow");
}
#[cfg(not(debug_assertions))]
{
a.wrapping_mul(D38::<SCALE>::multiplier()).wrapping_div(b)
}
}
#[cfg(test)]
mod tests {
use crate::core_type::D38s12;
#[test]
fn add_zero_to_zero_is_zero() {
assert_eq!(D38s12::ZERO + D38s12::ZERO, D38s12::ZERO);
}
#[test]
fn sub_zero_from_zero_is_zero() {
assert_eq!(D38s12::ZERO - D38s12::ZERO, D38s12::ZERO);
}
#[test]
fn neg_zero_is_zero() {
assert_eq!(-D38s12::ZERO, D38s12::ZERO);
}
#[test]
fn add_assign_zero() {
let mut v = D38s12::ZERO;
v += D38s12::ZERO;
assert_eq!(v, D38s12::ZERO);
}
#[test]
fn sub_assign_zero() {
let mut v = D38s12::ZERO;
v -= D38s12::ZERO;
assert_eq!(v, D38s12::ZERO);
}
#[test]
fn add_sub_round_trip_canonical_claim() {
let a = D38s12::from_bits(1_500_000_000_000);
let b = D38s12::from_bits(250_000_000_000);
assert_eq!((a + b) - b, a);
}
#[test]
fn add_sub_round_trip_negative() {
let a = D38s12::from_bits(-7_321_654_987_000);
let b = D38s12::from_bits(42_000_000_000_000);
assert_eq!((a + b) - b, a);
}
#[test]
fn one_plus_one_is_two_in_scaled_bits() {
let two = D38s12::ONE + D38s12::ONE;
assert_eq!(two.to_bits(), 2_000_000_000_000);
}
#[test]
fn neg_one_plus_one_is_zero() {
assert_eq!(-D38s12::ONE + D38s12::ONE, D38s12::ZERO);
}
#[test]
#[cfg(debug_assertions)]
#[should_panic(expected = "overflow")]
fn add_overflow_panics_in_debug() {
let _ = D38s12::MAX + D38s12::ONE;
}
#[test]
#[cfg(debug_assertions)]
#[should_panic(expected = "overflow")]
fn sub_underflow_panics_in_debug() {
let _ = D38s12::MIN - D38s12::ONE;
}
#[test]
#[cfg(debug_assertions)]
#[should_panic(expected = "overflow")]
fn neg_min_panics_in_debug() {
let _ = -D38s12::MIN;
}
#[test]
fn add_assign_accumulates() {
let mut v = D38s12::from_bits(100);
v += D38s12::from_bits(250);
assert_eq!(v.to_bits(), 350);
v += D38s12::from_bits(-50);
assert_eq!(v.to_bits(), 300);
}
#[test]
fn sub_assign_accumulates() {
let mut v = D38s12::from_bits(1000);
v -= D38s12::from_bits(250);
assert_eq!(v.to_bits(), 750);
}
#[test]
fn mul_one_one_is_one() {
assert_eq!(D38s12::ONE * D38s12::ONE, D38s12::ONE);
}
#[test]
fn div_one_one_is_one() {
assert_eq!(D38s12::ONE / D38s12::ONE, D38s12::ONE);
}
#[test]
fn rem_zero_one_is_zero() {
assert_eq!(D38s12::ZERO % D38s12::ONE, D38s12::ZERO);
}
#[test]
fn mul_zero_is_zero() {
let x = D38s12::from_bits(1_500_000_000_000); assert_eq!(D38s12::ZERO * x, D38s12::ZERO);
assert_eq!(x * D38s12::ZERO, D38s12::ZERO);
}
#[test]
fn mul_one_is_identity() {
let x = D38s12::from_bits(1_500_000_000_000); assert_eq!(D38s12::ONE * x, x);
assert_eq!(x * D38s12::ONE, x);
let y = D38s12::from_bits(-7_321_654_987_000); assert_eq!(D38s12::ONE * y, y);
assert_eq!(y * D38s12::ONE, y);
}
#[test]
fn div_one_is_identity() {
let x = D38s12::from_bits(1_500_000_000_000);
assert_eq!(x / D38s12::ONE, x);
let y = D38s12::from_bits(-7_321_654_987_000);
assert_eq!(y / D38s12::ONE, y);
}
#[test]
fn div_self_is_one() {
let x = D38s12::from_bits(1_500_000_000_000); assert_eq!(x / x, D38s12::ONE);
let y = D38s12::from_bits(-7_321_654_987_000);
assert_eq!(y / y, D38s12::ONE);
let small = D38s12::from_bits(1); assert_eq!(small / small, D38s12::ONE);
}
#[test]
fn rem_multiple_is_zero() {
let x = D38s12::from_bits(3_500_000_000_000); let seven = D38s12::ONE + D38s12::ONE + D38s12::ONE + D38s12::ONE
+ D38s12::ONE + D38s12::ONE + D38s12::ONE; assert_eq!((x * seven) % x, D38s12::ZERO);
}
#[test]
fn rem_self_is_zero() {
let x = D38s12::from_bits(1_500_000_000_000);
assert_eq!(x % x, D38s12::ZERO);
let y = D38s12::from_bits(-7_321_654_987_000);
assert_eq!(y % y, D38s12::ZERO);
}
#[test]
fn one_point_one_plus_two_point_two_equals_three_point_three() {
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);
}
#[test]
fn mul_round_trip_canonical_claim() {
let a = D38s12::from_bits(1_500_000_000_000);
let b = D38s12::from_bits(2_500_000_000_000);
let product = a * b;
assert_eq!(product, D38s12::from_bits(3_750_000_000_000));
assert_eq!(product / b, a);
let c = D38s12::from_bits(-7_321_654_987_000);
let d = D38s12::from_bits(13_000_000_000); let cd = c * d;
assert_eq!(cd / d, c);
}
#[test]
fn mul_assign_matches_mul() {
let a = D38s12::from_bits(1_500_000_000_000);
let b = D38s12::from_bits(2_500_000_000_000);
let mut x = a;
x *= b;
assert_eq!(x, a * b);
}
#[test]
fn div_assign_matches_div() {
let a = D38s12::from_bits(3_750_000_000_000);
let b = D38s12::from_bits(2_500_000_000_000);
let mut x = a;
x /= b;
assert_eq!(x, a / b);
}
#[test]
fn rem_assign_matches_rem() {
let a = D38s12::from_bits(7_500_000_000_000);
let b = D38s12::from_bits(2_000_000_000_000); let mut x = a;
x %= b;
assert_eq!(x, a % b);
}
#[test]
fn mul_is_commutative() {
let a = D38s12::from_bits(1_500_000_000_000);
let b = D38s12::from_bits(2_500_000_000_000);
assert_eq!(a * b, b * a);
}
#[test]
fn mul_subunit_rescales_exactly() {
let half = D38s12::from_bits(500_000_000_000); let quarter = D38s12::from_bits(250_000_000_000); assert_eq!(half * half, quarter);
}
#[test]
fn div_rescales_exactly() {
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);
}
#[test]
fn rem_truncates_toward_zero() {
let a = D38s12::from_bits(5_500_000_000_000);
let b = D38s12::from_bits(2_000_000_000_000);
let expected = D38s12::from_bits(1_500_000_000_000);
assert_eq!(a % b, expected);
let neg = D38s12::from_bits(-5_500_000_000_000);
let neg_expected = D38s12::from_bits(-1_500_000_000_000);
assert_eq!(neg % b, neg_expected);
}
#[test]
#[cfg(debug_assertions)]
#[should_panic(expected = "overflow")]
fn mul_overflow_panics_in_debug() {
let two = D38s12::from_bits(2_000_000_000_000);
let _ = D38s12::MAX * two;
}
#[test]
fn mul_wide_operands_match_widened_form() {
let a = D38s12::from_bits(50_000_000_000_000_000_000_000);
let b = D38s12::from_bits(30_000_000_000_000_000_000_000);
let expected = D38s12::from_bits(1_500_000_000_000_000_000_000_000_000_000_000);
assert_eq!(a * b, expected);
assert_eq!(b * a, expected);
}
#[test]
fn mul_div_wide_round_trip() {
let a = D38s12::from_bits(50_000_000_000_000_000_000_000);
let b = D38s12::from_bits(30_000_000_000_000_000_000_000);
let prod = a * b;
assert_eq!(prod / b, a);
}
#[test]
fn mul_wide_negative_signs() {
let a = D38s12::from_bits(50_000_000_000_000_000_000_000);
let b = D38s12::from_bits(30_000_000_000_000_000_000_000);
let neg_a = -a;
let neg_b = -b;
let pos_prod = a * b;
let neg_prod = -pos_prod;
assert_eq!(neg_a * b, neg_prod);
assert_eq!(a * neg_b, neg_prod);
assert_eq!(neg_a * neg_b, pos_prod);
}
#[test]
fn div_wide_dividend_correct() {
let a = D38s12::from_bits(10_i128.pow(22));
let b = D38s12::from_bits(2);
let expected = D38s12::from_bits(5 * 10_i128.pow(33));
assert_eq!(a / b, expected);
}
#[test]
fn div_wide_round_trip_exact() {
let a = D38s12::from_bits(10_i128.pow(27));
let b = D38s12::from_bits(100);
let q = a / b;
let expected = D38s12::from_bits(10_i128.pow(37));
assert_eq!(q, expected);
}
#[test]
fn div_scale_zero_matches_i128_div() {
if !crate::rounding::DEFAULT_IS_HALF_TO_EVEN {
return;
}
type D0 = crate::core_type::D38<0>;
let a = D0::from_bits(15);
let b = D0::from_bits(4);
assert_eq!(a / b, D0::from_bits(4));
assert_eq!((-a) / b, D0::from_bits(-4));
let c = D0::from_bits(16);
assert_eq!(c / b, D0::from_bits(4));
}
#[test]
fn mul_scale_zero_matches_i128_mul() {
type D0 = crate::core_type::D38<0>;
let a = D0::from_bits(7);
let b = D0::from_bits(11);
assert_eq!(a * b, D0::from_bits(77));
assert_eq!((-a) * b, D0::from_bits(-77));
}
#[test]
#[should_panic]
fn div_by_zero_panics() {
let _ = D38s12::ONE / D38s12::ZERO;
}
#[test]
#[should_panic]
fn rem_by_zero_panics() {
let _ = D38s12::ONE % D38s12::ZERO;
}
#[test]
fn abs_zero_is_zero() {
assert_eq!(D38s12::ZERO.abs(), D38s12::ZERO);
}
#[test]
fn abs_positive_is_self() {
let x = D38s12::from_bits(1_500_000_000_000); assert_eq!(x.abs(), x);
}
#[test]
fn abs_negative_is_positive() {
let neg = D38s12::from_bits(-1_500_000_000_000);
let pos = D38s12::from_bits(1_500_000_000_000);
assert_eq!(neg.abs(), pos);
}
#[test]
#[cfg(debug_assertions)]
#[should_panic(expected = "overflow")]
fn abs_min_panics_in_debug() {
let _ = D38s12::MIN.abs();
}
#[test]
fn signum_zero_is_zero() {
assert_eq!(D38s12::ZERO.signum(), D38s12::ZERO);
}
#[test]
fn signum_positive_is_one() {
let x = D38s12::from_bits(1_500_000_000_000);
assert_eq!(x.signum(), D38s12::ONE);
let tiny = D38s12::from_bits(1);
assert_eq!(tiny.signum(), D38s12::ONE);
}
#[test]
fn signum_negative_is_neg_one() {
let x = D38s12::from_bits(-1_500_000_000_000);
assert_eq!(x.signum(), -D38s12::ONE);
let tiny_neg = D38s12::from_bits(-1);
assert_eq!(tiny_neg.signum(), -D38s12::ONE);
}
#[test]
fn floor_positive_fractional_rounds_down() {
let x = D38s12::from_bits(2_500_000_000_000);
let expected = D38s12::from_bits(2_000_000_000_000);
assert_eq!(x.floor(), expected);
}
#[test]
fn floor_negative_fractional_rounds_down_toward_neg_inf() {
let x = D38s12::from_bits(-2_500_000_000_000);
let expected = D38s12::from_bits(-3_000_000_000_000);
assert_eq!(x.floor(), expected);
let small_neg = D38s12::from_bits(-500_000_000_000);
let small_expected = D38s12::from_bits(-1_000_000_000_000);
assert_eq!(small_neg.floor(), small_expected);
}
#[test]
fn floor_integer_unchanged() {
let two = D38s12::from_bits(2_000_000_000_000);
assert_eq!(two.floor(), two);
let neg_two = D38s12::from_bits(-2_000_000_000_000);
assert_eq!(neg_two.floor(), neg_two);
assert_eq!(D38s12::ZERO.floor(), D38s12::ZERO);
}
#[test]
fn ceil_positive_fractional_rounds_up() {
let x = D38s12::from_bits(2_500_000_000_000);
let expected = D38s12::from_bits(3_000_000_000_000);
assert_eq!(x.ceil(), expected);
}
#[test]
fn ceil_negative_fractional_rounds_up_toward_pos_inf() {
let x = D38s12::from_bits(-2_500_000_000_000);
let expected = D38s12::from_bits(-2_000_000_000_000);
assert_eq!(x.ceil(), expected);
let small_neg = D38s12::from_bits(-500_000_000_000);
assert_eq!(small_neg.ceil(), D38s12::ZERO);
}
#[test]
fn ceil_integer_unchanged() {
let two = D38s12::from_bits(2_000_000_000_000);
assert_eq!(two.ceil(), two);
let neg_two = D38s12::from_bits(-2_000_000_000_000);
assert_eq!(neg_two.ceil(), neg_two);
assert_eq!(D38s12::ZERO.ceil(), D38s12::ZERO);
}
#[test]
fn round_half_away_from_zero() {
let two_point_five = D38s12::from_bits(2_500_000_000_000);
assert_eq!(two_point_five.round(), D38s12::from_bits(3_000_000_000_000));
let two_point_four = D38s12::from_bits(2_400_000_000_000);
assert_eq!(two_point_four.round(), D38s12::from_bits(2_000_000_000_000));
let two_point_six = D38s12::from_bits(2_600_000_000_000);
assert_eq!(two_point_six.round(), D38s12::from_bits(3_000_000_000_000));
let neg_two_point_five = D38s12::from_bits(-2_500_000_000_000);
assert_eq!(neg_two_point_five.round(), D38s12::from_bits(-3_000_000_000_000));
let neg_two_point_four = D38s12::from_bits(-2_400_000_000_000);
assert_eq!(neg_two_point_four.round(), D38s12::from_bits(-2_000_000_000_000));
let neg_two_point_six = D38s12::from_bits(-2_600_000_000_000);
assert_eq!(neg_two_point_six.round(), D38s12::from_bits(-3_000_000_000_000));
assert_eq!(D38s12::ZERO.round(), D38s12::ZERO);
}
#[test]
fn trunc_drops_fractional() {
let x = D38s12::from_bits(2_500_000_000_000);
assert_eq!(x.trunc(), D38s12::from_bits(2_000_000_000_000));
let neg = D38s12::from_bits(-2_500_000_000_000);
assert_eq!(neg.trunc(), D38s12::from_bits(-2_000_000_000_000));
assert_eq!(D38s12::ZERO.trunc(), D38s12::ZERO);
let two = D38s12::from_bits(2_000_000_000_000);
assert_eq!(two.trunc(), two);
}
#[test]
fn fract_keeps_only_fractional() {
let x = D38s12::from_bits(2_500_000_000_000);
assert_eq!(x.fract(), D38s12::from_bits(500_000_000_000));
let neg = D38s12::from_bits(-2_500_000_000_000);
assert_eq!(neg.fract(), D38s12::from_bits(-500_000_000_000));
let two = D38s12::from_bits(2_000_000_000_000);
assert_eq!(two.fract(), D38s12::ZERO);
assert_eq!(D38s12::ZERO.fract(), D38s12::ZERO);
}
#[test]
fn trunc_plus_fract_equals_self() {
let cases = [
D38s12::from_bits(2_500_000_000_000),
D38s12::from_bits(-2_500_000_000_000),
D38s12::from_bits(7_321_654_987_000),
D38s12::from_bits(-7_321_654_987_000),
D38s12::ZERO,
D38s12::ONE,
-D38s12::ONE,
D38s12::from_bits(1), D38s12::from_bits(-1),
];
for x in cases {
assert_eq!(x.trunc() + x.fract(), x, "failed for {:?}", x);
}
}
#[test]
fn min_max_clamp_basic() {
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);
assert_eq!(b.min(a), a);
assert_eq!(a.max(b), b);
assert_eq!(b.max(a), b);
assert_eq!(b.clamp(a, c), b);
assert_eq!(D38s12::ZERO.clamp(a, c), a);
let four = D38s12::from_bits(4_000_000_000_000);
assert_eq!(four.clamp(a, c), c);
let neg_a = -a;
let neg_b = -b;
assert_eq!(neg_a.min(neg_b), neg_b); assert_eq!(neg_a.max(neg_b), neg_a);
}
#[test]
fn recip_inverts_known_values() {
let two = D38s12::from_bits(2_000_000_000_000);
let half = D38s12::from_bits(500_000_000_000);
assert_eq!(two.recip(), half);
assert_eq!(half.recip(), two);
assert_eq!(D38s12::ONE.recip(), D38s12::ONE);
assert_eq!((-D38s12::ONE).recip(), -D38s12::ONE);
}
#[test]
#[should_panic]
fn recip_zero_panics() {
let _ = D38s12::ZERO.recip();
}
#[test]
fn copysign_basic() {
let pos = D38s12::from_bits(1_500_000_000_000);
let neg = D38s12::from_bits(-1_500_000_000_000);
assert_eq!(pos.copysign(pos), pos);
assert_eq!(pos.copysign(neg), neg);
assert_eq!(neg.copysign(pos), pos);
assert_eq!(neg.copysign(neg), neg);
}
#[test]
fn copysign_zero() {
let neg = D38s12::from_bits(-1_500_000_000_000);
let pos = D38s12::from_bits(1_500_000_000_000);
assert_eq!(neg.copysign(D38s12::ZERO), pos);
assert_eq!(pos.copysign(D38s12::ZERO), pos);
assert_eq!(D38s12::ZERO.copysign(neg), D38s12::ZERO);
assert_eq!(D38s12::ZERO.copysign(pos), D38s12::ZERO);
}
#[test]
fn div_euclid_positive() {
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);
assert_eq!(q, D38s12::from_bits(2_000_000_000_000));
let r = a.rem_euclid(b);
assert_eq!(r, D38s12::from_bits(1_000_000_000_000));
assert_eq!(q * b + r, a);
}
#[test]
fn div_euclid_negative_dividend() {
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);
assert_eq!(q, D38s12::from_bits(-3_000_000_000_000));
let r = a.rem_euclid(b);
assert_eq!(r, D38s12::from_bits(1_000_000_000_000));
assert_eq!(q * b + r, a);
}
#[test]
fn div_euclid_negative_divisor() {
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);
assert_eq!(q, D38s12::from_bits(-2_000_000_000_000));
let r = a.rem_euclid(b);
assert_eq!(r, D38s12::from_bits(1_000_000_000_000));
assert_eq!(q * b + r, a);
}
#[test]
fn rem_euclid_consistency_with_div_euclid() {
let cases: &[(i128, i128)] = &[
(5_000_000_000_000, 2_000_000_000_000),
(-5_000_000_000_000, 2_000_000_000_000),
(5_000_000_000_000, -2_000_000_000_000),
(-5_000_000_000_000, -2_000_000_000_000),
(7_321_654_987_000, 13_000_000_000),
(-7_321_654_987_000, 13_000_000_000),
];
for (a_bits, b_bits) in cases {
let a = D38s12::from_bits(*a_bits);
let b = D38s12::from_bits(*b_bits);
let q = a.div_euclid(b);
let r = a.rem_euclid(b);
assert_eq!(q * b + r, a, "failed for a={}, b={}", a_bits, b_bits);
assert!(r.0 >= 0, "rem_euclid returned negative for a={}, b={}: {}",
a_bits, b_bits, r.0);
}
}
#[test]
fn div_floor_basic() {
let a = D38s12::from_bits(5_000_000_000_000);
let b = D38s12::from_bits(2_000_000_000_000);
assert_eq!(a.div_floor(b), D38s12::from_bits(2_000_000_000_000));
let neg_a = D38s12::from_bits(-5_000_000_000_000);
assert_eq!(neg_a.div_floor(b), D38s12::from_bits(-3_000_000_000_000));
let neg_b = D38s12::from_bits(-2_000_000_000_000);
assert_eq!(neg_a.div_floor(neg_b), D38s12::from_bits(2_000_000_000_000));
assert_eq!(a.div_floor(neg_b), D38s12::from_bits(-3_000_000_000_000));
}
#[test]
fn div_ceil_basic() {
let a = D38s12::from_bits(5_000_000_000_000);
let b = D38s12::from_bits(2_000_000_000_000);
assert_eq!(a.div_ceil(b), D38s12::from_bits(3_000_000_000_000));
let neg_a = D38s12::from_bits(-5_000_000_000_000);
assert_eq!(neg_a.div_ceil(b), D38s12::from_bits(-2_000_000_000_000));
let four = D38s12::from_bits(4_000_000_000_000);
assert_eq!(four.div_ceil(b), D38s12::from_bits(2_000_000_000_000));
}
#[test]
fn abs_diff_commutative() {
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);
assert_eq!(b.abs_diff(a), expected);
let neg_a = -a;
let neg_b = -b;
assert_eq!(neg_a.abs_diff(neg_b), expected);
assert_eq!(neg_b.abs_diff(neg_a), expected);
let seven = D38s12::from_bits(7_000_000_000_000);
assert_eq!(a.abs_diff(neg_b), seven);
assert_eq!(neg_b.abs_diff(a), seven);
}
#[test]
fn abs_diff_zero() {
let x = D38s12::from_bits(1_500_000_000_000);
assert_eq!(x.abs_diff(x), D38s12::ZERO);
assert_eq!(x.abs_diff(D38s12::ZERO), x.abs());
let neg = -x;
assert_eq!(neg.abs_diff(D38s12::ZERO), x);
}
#[test]
fn midpoint_basic() {
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;
let neg_b = -b;
assert_eq!(neg_a.midpoint(neg_b), D38s12::from_bits(-2_000_000_000_000));
assert_eq!(neg_a.midpoint(a), D38s12::ZERO);
}
#[test]
fn midpoint_no_overflow_at_max() {
assert_eq!(D38s12::MAX.midpoint(D38s12::MAX), D38s12::MAX);
assert_eq!(D38s12::MIN.midpoint(D38s12::MIN), D38s12::MIN);
let mid = D38s12::MIN.midpoint(D38s12::MAX);
assert!(mid.0 == 0 || mid.0 == -1,
"midpoint(MIN, MAX) should be 0 or -1, got {}", mid.0);
}
#[test]
fn is_nan_always_false() {
assert!(!D38s12::ZERO.is_nan());
assert!(!D38s12::ONE.is_nan());
assert!(!D38s12::MAX.is_nan());
assert!(!D38s12::MIN.is_nan());
}
#[test]
fn is_infinite_always_false() {
assert!(!D38s12::ZERO.is_infinite());
assert!(!D38s12::MAX.is_infinite());
assert!(!D38s12::MIN.is_infinite());
}
#[test]
fn is_finite_always_true() {
assert!(D38s12::ZERO.is_finite());
assert!(D38s12::ONE.is_finite());
assert!(D38s12::MAX.is_finite());
assert!(D38s12::MIN.is_finite());
}
#[test]
fn is_normal_zero_is_false() {
assert!(!D38s12::ZERO.is_normal());
}
#[test]
fn is_normal_nonzero_is_true() {
assert!(D38s12::ONE.is_normal());
assert!((-D38s12::ONE).is_normal());
assert!(D38s12::from_bits(1).is_normal()); assert!(D38s12::from_bits(-1).is_normal()); assert!(D38s12::MAX.is_normal());
assert!(D38s12::MIN.is_normal());
}
#[test]
fn is_zero_predicates() {
assert!(D38s12::ZERO.is_zero());
assert!(!D38s12::ZERO.is_positive());
assert!(!D38s12::ZERO.is_negative());
assert!(!D38s12::from_bits(1).is_zero());
assert!(D38s12::from_bits(1).is_positive());
assert!(!D38s12::from_bits(1).is_negative());
assert!(!D38s12::from_bits(-1).is_zero());
assert!(!D38s12::from_bits(-1).is_positive());
assert!(D38s12::from_bits(-1).is_negative());
}
}