use core::ops::{
Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Rem, RemAssign, Sub, SubAssign,
};
use crate::core_type::I128;
impl<const SCALE: u32> Add for I128<SCALE> {
type Output = Self;
#[inline]
fn add(self, rhs: Self) -> Self {
Self(self.0 + rhs.0)
}
}
impl<const SCALE: u32> AddAssign for I128<SCALE> {
#[inline]
fn add_assign(&mut self, rhs: Self) {
self.0 += rhs.0;
}
}
impl<const SCALE: u32> Sub for I128<SCALE> {
type Output = Self;
#[inline]
fn sub(self, rhs: Self) -> Self {
Self(self.0 - rhs.0)
}
}
impl<const SCALE: u32> SubAssign for I128<SCALE> {
#[inline]
fn sub_assign(&mut self, rhs: Self) {
self.0 -= rhs.0;
}
}
impl<const SCALE: u32> Neg for I128<SCALE> {
type Output = Self;
#[inline]
fn neg(self) -> Self {
Self(-self.0)
}
}
impl<const SCALE: u32> Mul for I128<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 I128<SCALE> {
#[inline]
fn mul_assign(&mut self, rhs: Self) {
*self = *self * rhs;
}
}
impl<const SCALE: u32> Div for I128<SCALE> {
type Output = Self;
#[inline]
fn div(self, rhs: Self) -> Self {
if rhs.0 == 0 {
panic!("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 I128<SCALE> {
#[inline]
fn div_assign(&mut self, rhs: Self) {
*self = *self / rhs;
}
}
#[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(I128::<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(I128::<SCALE>::multiplier()).wrapping_div(b)
}
}
impl<const SCALE: u32> Rem for I128<SCALE> {
type Output = Self;
#[inline]
fn rem(self, rhs: Self) -> Self {
Self(self.0 % rhs.0)
}
}
impl<const SCALE: u32> RemAssign for I128<SCALE> {
#[inline]
fn rem_assign(&mut self, rhs: Self) {
self.0 %= rhs.0;
}
}
impl<const SCALE: u32> I128<SCALE> {
#[inline]
pub const fn abs(self) -> Self {
Self(self.0.abs())
}
#[inline]
pub fn signum(self) -> Self {
match self.0.signum() {
1 => Self::ONE,
-1 => Self(-Self::multiplier()),
_ => Self::ZERO,
}
}
#[inline]
pub fn floor(self) -> Self {
let m = Self::multiplier();
Self(self.0.div_euclid(m) * m)
}
#[inline]
pub fn ceil(self) -> Self {
let m = Self::multiplier();
Self(-((-self.0).div_euclid(m)) * m)
}
#[inline]
pub fn round(self) -> Self {
let m = Self::multiplier();
let half = m / 2;
let bias = if self.0 >= 0 { half } else { -half };
Self((self.0 + bias) / m * m)
}
#[inline]
pub fn trunc(self) -> Self {
let m = Self::multiplier();
Self(self.0 / m * m)
}
#[inline]
pub fn fract(self) -> Self {
let m = Self::multiplier();
Self(self.0 - (self.0 / m * m))
}
#[inline]
pub fn min(self, other: Self) -> Self {
Self(self.0.min(other.0))
}
#[inline]
pub fn max(self, other: Self) -> Self {
Self(self.0.max(other.0))
}
#[inline]
pub fn clamp(self, lo: Self, hi: Self) -> Self {
Self(self.0.clamp(lo.0, hi.0))
}
#[inline]
pub fn recip(self) -> Self {
Self::ONE / self
}
#[inline]
pub fn copysign(self, sign: Self) -> Self {
let mag = self.0.abs();
if sign.0 < 0 { Self(-mag) } else { Self(mag) }
}
#[inline]
pub fn div_euclid(self, rhs: Self) -> Self {
Self(self.0.div_euclid(rhs.0) * Self::multiplier())
}
#[inline]
pub fn rem_euclid(self, rhs: Self) -> Self {
Self(self.0.rem_euclid(rhs.0))
}
#[inline]
pub fn div_floor(self, rhs: Self) -> Self {
let q = self.0 / rhs.0;
let r = self.0 % rhs.0;
let raw = if r != 0 && (r ^ rhs.0) < 0 { q - 1 } else { q };
Self(raw * Self::multiplier())
}
#[inline]
pub fn div_ceil(self, rhs: Self) -> Self {
let q = self.0 / rhs.0;
let r = self.0 % rhs.0;
let raw = if r != 0 && (r ^ rhs.0) >= 0 { q + 1 } else { q };
Self(raw * Self::multiplier())
}
#[inline]
pub fn abs_diff(self, rhs: Self) -> Self {
Self(self.0.max(rhs.0) - self.0.min(rhs.0))
}
#[inline]
pub fn midpoint(self, rhs: Self) -> Self {
Self(self.0.midpoint(rhs.0))
}
#[inline]
pub const fn is_nan(self) -> bool {
false
}
#[inline]
pub const fn is_infinite(self) -> bool {
false
}
#[inline]
pub const fn is_finite(self) -> bool {
true
}
#[inline]
pub const fn is_normal(self) -> bool {
self.0 != 0
}
#[inline]
pub const fn is_zero(self) -> bool {
self.0 == 0
}
#[inline]
pub const fn is_positive(self) -> bool {
self.0 > 0
}
#[inline]
pub const fn is_negative(self) -> bool {
self.0 < 0
}
}
#[cfg(test)]
mod tests {
use crate::core_type::I128s12;
#[test]
fn add_zero_to_zero_is_zero() {
assert_eq!(I128s12::ZERO + I128s12::ZERO, I128s12::ZERO);
}
#[test]
fn sub_zero_from_zero_is_zero() {
assert_eq!(I128s12::ZERO - I128s12::ZERO, I128s12::ZERO);
}
#[test]
fn neg_zero_is_zero() {
assert_eq!(-I128s12::ZERO, I128s12::ZERO);
}
#[test]
fn add_assign_zero() {
let mut v = I128s12::ZERO;
v += I128s12::ZERO;
assert_eq!(v, I128s12::ZERO);
}
#[test]
fn sub_assign_zero() {
let mut v = I128s12::ZERO;
v -= I128s12::ZERO;
assert_eq!(v, I128s12::ZERO);
}
#[test]
fn add_sub_round_trip_canonical_claim() {
let a = I128s12::from_bits(1_500_000_000_000);
let b = I128s12::from_bits(250_000_000_000);
assert_eq!((a + b) - b, a);
}
#[test]
fn add_sub_round_trip_negative() {
let a = I128s12::from_bits(-7_321_654_987_000);
let b = I128s12::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 = I128s12::ONE + I128s12::ONE;
assert_eq!(two.to_bits(), 2_000_000_000_000);
}
#[test]
fn neg_one_plus_one_is_zero() {
assert_eq!(-I128s12::ONE + I128s12::ONE, I128s12::ZERO);
}
#[test]
#[cfg(debug_assertions)]
#[should_panic(expected = "overflow")]
fn add_overflow_panics_in_debug() {
let _ = I128s12::MAX + I128s12::ONE;
}
#[test]
#[cfg(debug_assertions)]
#[should_panic(expected = "overflow")]
fn sub_underflow_panics_in_debug() {
let _ = I128s12::MIN - I128s12::ONE;
}
#[test]
#[cfg(debug_assertions)]
#[should_panic(expected = "overflow")]
fn neg_min_panics_in_debug() {
let _ = -I128s12::MIN;
}
#[test]
fn add_assign_accumulates() {
let mut v = I128s12::from_bits(100);
v += I128s12::from_bits(250);
assert_eq!(v.to_bits(), 350);
v += I128s12::from_bits(-50);
assert_eq!(v.to_bits(), 300);
}
#[test]
fn sub_assign_accumulates() {
let mut v = I128s12::from_bits(1000);
v -= I128s12::from_bits(250);
assert_eq!(v.to_bits(), 750);
}
#[test]
fn mul_one_one_is_one() {
assert_eq!(I128s12::ONE * I128s12::ONE, I128s12::ONE);
}
#[test]
fn div_one_one_is_one() {
assert_eq!(I128s12::ONE / I128s12::ONE, I128s12::ONE);
}
#[test]
fn rem_zero_one_is_zero() {
assert_eq!(I128s12::ZERO % I128s12::ONE, I128s12::ZERO);
}
#[test]
fn mul_zero_is_zero() {
let x = I128s12::from_bits(1_500_000_000_000); assert_eq!(I128s12::ZERO * x, I128s12::ZERO);
assert_eq!(x * I128s12::ZERO, I128s12::ZERO);
}
#[test]
fn mul_one_is_identity() {
let x = I128s12::from_bits(1_500_000_000_000); assert_eq!(I128s12::ONE * x, x);
assert_eq!(x * I128s12::ONE, x);
let y = I128s12::from_bits(-7_321_654_987_000); assert_eq!(I128s12::ONE * y, y);
assert_eq!(y * I128s12::ONE, y);
}
#[test]
fn div_one_is_identity() {
let x = I128s12::from_bits(1_500_000_000_000);
assert_eq!(x / I128s12::ONE, x);
let y = I128s12::from_bits(-7_321_654_987_000);
assert_eq!(y / I128s12::ONE, y);
}
#[test]
fn div_self_is_one() {
let x = I128s12::from_bits(1_500_000_000_000); assert_eq!(x / x, I128s12::ONE);
let y = I128s12::from_bits(-7_321_654_987_000);
assert_eq!(y / y, I128s12::ONE);
let small = I128s12::from_bits(1); assert_eq!(small / small, I128s12::ONE);
}
#[test]
fn rem_multiple_is_zero() {
let x = I128s12::from_bits(3_500_000_000_000); let seven = I128s12::ONE + I128s12::ONE + I128s12::ONE + I128s12::ONE
+ I128s12::ONE + I128s12::ONE + I128s12::ONE; assert_eq!((x * seven) % x, I128s12::ZERO);
}
#[test]
fn rem_self_is_zero() {
let x = I128s12::from_bits(1_500_000_000_000);
assert_eq!(x % x, I128s12::ZERO);
let y = I128s12::from_bits(-7_321_654_987_000);
assert_eq!(y % y, I128s12::ZERO);
}
#[test]
fn one_point_one_plus_two_point_two_equals_three_point_three() {
let one_point_one = I128s12::from_bits(1_100_000_000_000); let two_point_two = I128s12::from_bits(2_200_000_000_000); let three_point_three = I128s12::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 = I128s12::from_bits(1_500_000_000_000);
let b = I128s12::from_bits(2_500_000_000_000);
let product = a * b;
assert_eq!(product, I128s12::from_bits(3_750_000_000_000));
assert_eq!(product / b, a);
let c = I128s12::from_bits(-7_321_654_987_000);
let d = I128s12::from_bits(13_000_000_000); let cd = c * d;
assert_eq!(cd / d, c);
}
#[test]
fn mul_assign_matches_mul() {
let a = I128s12::from_bits(1_500_000_000_000);
let b = I128s12::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 = I128s12::from_bits(3_750_000_000_000);
let b = I128s12::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 = I128s12::from_bits(7_500_000_000_000);
let b = I128s12::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 = I128s12::from_bits(1_500_000_000_000);
let b = I128s12::from_bits(2_500_000_000_000);
assert_eq!(a * b, b * a);
}
#[test]
fn mul_subunit_rescales_exactly() {
let half = I128s12::from_bits(500_000_000_000); let quarter = I128s12::from_bits(250_000_000_000); assert_eq!(half * half, quarter);
}
#[test]
fn div_rescales_exactly() {
let half = I128s12::from_bits(500_000_000_000); let two = I128s12::from_bits(2_000_000_000_000); let quarter = I128s12::from_bits(250_000_000_000); assert_eq!(half / two, quarter);
}
#[test]
fn rem_truncates_toward_zero() {
let a = I128s12::from_bits(5_500_000_000_000);
let b = I128s12::from_bits(2_000_000_000_000);
let expected = I128s12::from_bits(1_500_000_000_000);
assert_eq!(a % b, expected);
let neg = I128s12::from_bits(-5_500_000_000_000);
let neg_expected = I128s12::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 = I128s12::from_bits(2_000_000_000_000);
let _ = I128s12::MAX * two;
}
#[test]
fn mul_wide_operands_match_widened_form() {
let a = I128s12::from_bits(50_000_000_000_000_000_000_000);
let b = I128s12::from_bits(30_000_000_000_000_000_000_000);
let expected = I128s12::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 = I128s12::from_bits(50_000_000_000_000_000_000_000);
let b = I128s12::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 = I128s12::from_bits(50_000_000_000_000_000_000_000);
let b = I128s12::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 = I128s12::from_bits(10_i128.pow(22));
let b = I128s12::from_bits(2);
let expected = I128s12::from_bits(5 * 10_i128.pow(33));
assert_eq!(a / b, expected);
}
#[test]
fn div_wide_round_trip_exact() {
let a = I128s12::from_bits(10_i128.pow(27));
let b = I128s12::from_bits(100);
let q = a / b;
let expected = I128s12::from_bits(10_i128.pow(37));
assert_eq!(q, expected);
}
#[test]
fn div_scale_zero_matches_i128_div() {
type D0 = crate::core_type::I128<0>;
let a = D0::from_bits(15);
let b = D0::from_bits(4);
assert_eq!(a / b, D0::from_bits(3));
assert_eq!((-a) / b, D0::from_bits(-3));
}
#[test]
fn mul_scale_zero_matches_i128_mul() {
type D0 = crate::core_type::I128<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 _ = I128s12::ONE / I128s12::ZERO;
}
#[test]
#[should_panic]
fn rem_by_zero_panics() {
let _ = I128s12::ONE % I128s12::ZERO;
}
#[test]
fn abs_zero_is_zero() {
assert_eq!(I128s12::ZERO.abs(), I128s12::ZERO);
}
#[test]
fn abs_positive_is_self() {
let x = I128s12::from_bits(1_500_000_000_000); assert_eq!(x.abs(), x);
}
#[test]
fn abs_negative_is_positive() {
let neg = I128s12::from_bits(-1_500_000_000_000);
let pos = I128s12::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 _ = I128s12::MIN.abs();
}
#[test]
fn signum_zero_is_zero() {
assert_eq!(I128s12::ZERO.signum(), I128s12::ZERO);
}
#[test]
fn signum_positive_is_one() {
let x = I128s12::from_bits(1_500_000_000_000);
assert_eq!(x.signum(), I128s12::ONE);
let tiny = I128s12::from_bits(1);
assert_eq!(tiny.signum(), I128s12::ONE);
}
#[test]
fn signum_negative_is_neg_one() {
let x = I128s12::from_bits(-1_500_000_000_000);
assert_eq!(x.signum(), -I128s12::ONE);
let tiny_neg = I128s12::from_bits(-1);
assert_eq!(tiny_neg.signum(), -I128s12::ONE);
}
#[test]
fn floor_positive_fractional_rounds_down() {
let x = I128s12::from_bits(2_500_000_000_000);
let expected = I128s12::from_bits(2_000_000_000_000);
assert_eq!(x.floor(), expected);
}
#[test]
fn floor_negative_fractional_rounds_down_toward_neg_inf() {
let x = I128s12::from_bits(-2_500_000_000_000);
let expected = I128s12::from_bits(-3_000_000_000_000);
assert_eq!(x.floor(), expected);
let small_neg = I128s12::from_bits(-500_000_000_000);
let small_expected = I128s12::from_bits(-1_000_000_000_000);
assert_eq!(small_neg.floor(), small_expected);
}
#[test]
fn floor_integer_unchanged() {
let two = I128s12::from_bits(2_000_000_000_000);
assert_eq!(two.floor(), two);
let neg_two = I128s12::from_bits(-2_000_000_000_000);
assert_eq!(neg_two.floor(), neg_two);
assert_eq!(I128s12::ZERO.floor(), I128s12::ZERO);
}
#[test]
fn ceil_positive_fractional_rounds_up() {
let x = I128s12::from_bits(2_500_000_000_000);
let expected = I128s12::from_bits(3_000_000_000_000);
assert_eq!(x.ceil(), expected);
}
#[test]
fn ceil_negative_fractional_rounds_up_toward_pos_inf() {
let x = I128s12::from_bits(-2_500_000_000_000);
let expected = I128s12::from_bits(-2_000_000_000_000);
assert_eq!(x.ceil(), expected);
let small_neg = I128s12::from_bits(-500_000_000_000);
assert_eq!(small_neg.ceil(), I128s12::ZERO);
}
#[test]
fn ceil_integer_unchanged() {
let two = I128s12::from_bits(2_000_000_000_000);
assert_eq!(two.ceil(), two);
let neg_two = I128s12::from_bits(-2_000_000_000_000);
assert_eq!(neg_two.ceil(), neg_two);
assert_eq!(I128s12::ZERO.ceil(), I128s12::ZERO);
}
#[test]
fn round_half_away_from_zero() {
let two_point_five = I128s12::from_bits(2_500_000_000_000);
assert_eq!(two_point_five.round(), I128s12::from_bits(3_000_000_000_000));
let two_point_four = I128s12::from_bits(2_400_000_000_000);
assert_eq!(two_point_four.round(), I128s12::from_bits(2_000_000_000_000));
let two_point_six = I128s12::from_bits(2_600_000_000_000);
assert_eq!(two_point_six.round(), I128s12::from_bits(3_000_000_000_000));
let neg_two_point_five = I128s12::from_bits(-2_500_000_000_000);
assert_eq!(neg_two_point_five.round(), I128s12::from_bits(-3_000_000_000_000));
let neg_two_point_four = I128s12::from_bits(-2_400_000_000_000);
assert_eq!(neg_two_point_four.round(), I128s12::from_bits(-2_000_000_000_000));
let neg_two_point_six = I128s12::from_bits(-2_600_000_000_000);
assert_eq!(neg_two_point_six.round(), I128s12::from_bits(-3_000_000_000_000));
assert_eq!(I128s12::ZERO.round(), I128s12::ZERO);
}
#[test]
fn trunc_drops_fractional() {
let x = I128s12::from_bits(2_500_000_000_000);
assert_eq!(x.trunc(), I128s12::from_bits(2_000_000_000_000));
let neg = I128s12::from_bits(-2_500_000_000_000);
assert_eq!(neg.trunc(), I128s12::from_bits(-2_000_000_000_000));
assert_eq!(I128s12::ZERO.trunc(), I128s12::ZERO);
let two = I128s12::from_bits(2_000_000_000_000);
assert_eq!(two.trunc(), two);
}
#[test]
fn fract_keeps_only_fractional() {
let x = I128s12::from_bits(2_500_000_000_000);
assert_eq!(x.fract(), I128s12::from_bits(500_000_000_000));
let neg = I128s12::from_bits(-2_500_000_000_000);
assert_eq!(neg.fract(), I128s12::from_bits(-500_000_000_000));
let two = I128s12::from_bits(2_000_000_000_000);
assert_eq!(two.fract(), I128s12::ZERO);
assert_eq!(I128s12::ZERO.fract(), I128s12::ZERO);
}
#[test]
fn trunc_plus_fract_equals_self() {
let cases = [
I128s12::from_bits(2_500_000_000_000),
I128s12::from_bits(-2_500_000_000_000),
I128s12::from_bits(7_321_654_987_000),
I128s12::from_bits(-7_321_654_987_000),
I128s12::ZERO,
I128s12::ONE,
-I128s12::ONE,
I128s12::from_bits(1), I128s12::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 = I128s12::from_bits(1_000_000_000_000); let b = I128s12::from_bits(2_000_000_000_000); let c = I128s12::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!(I128s12::ZERO.clamp(a, c), a);
let four = I128s12::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 = I128s12::from_bits(2_000_000_000_000);
let half = I128s12::from_bits(500_000_000_000);
assert_eq!(two.recip(), half);
assert_eq!(half.recip(), two);
assert_eq!(I128s12::ONE.recip(), I128s12::ONE);
assert_eq!((-I128s12::ONE).recip(), -I128s12::ONE);
}
#[test]
#[should_panic]
fn recip_zero_panics() {
let _ = I128s12::ZERO.recip();
}
#[test]
fn copysign_basic() {
let pos = I128s12::from_bits(1_500_000_000_000);
let neg = I128s12::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 = I128s12::from_bits(-1_500_000_000_000);
let pos = I128s12::from_bits(1_500_000_000_000);
assert_eq!(neg.copysign(I128s12::ZERO), pos);
assert_eq!(pos.copysign(I128s12::ZERO), pos);
assert_eq!(I128s12::ZERO.copysign(neg), I128s12::ZERO);
assert_eq!(I128s12::ZERO.copysign(pos), I128s12::ZERO);
}
#[test]
fn div_euclid_positive() {
let a = I128s12::from_bits(5_000_000_000_000); let b = I128s12::from_bits(2_000_000_000_000);
let q = a.div_euclid(b);
assert_eq!(q, I128s12::from_bits(2_000_000_000_000));
let r = a.rem_euclid(b);
assert_eq!(r, I128s12::from_bits(1_000_000_000_000));
assert_eq!(q * b + r, a);
}
#[test]
fn div_euclid_negative_dividend() {
let a = I128s12::from_bits(-5_000_000_000_000); let b = I128s12::from_bits(2_000_000_000_000);
let q = a.div_euclid(b);
assert_eq!(q, I128s12::from_bits(-3_000_000_000_000));
let r = a.rem_euclid(b);
assert_eq!(r, I128s12::from_bits(1_000_000_000_000));
assert_eq!(q * b + r, a);
}
#[test]
fn div_euclid_negative_divisor() {
let a = I128s12::from_bits(5_000_000_000_000); let b = I128s12::from_bits(-2_000_000_000_000);
let q = a.div_euclid(b);
assert_eq!(q, I128s12::from_bits(-2_000_000_000_000));
let r = a.rem_euclid(b);
assert_eq!(r, I128s12::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 = I128s12::from_bits(*a_bits);
let b = I128s12::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 = I128s12::from_bits(5_000_000_000_000);
let b = I128s12::from_bits(2_000_000_000_000);
assert_eq!(a.div_floor(b), I128s12::from_bits(2_000_000_000_000));
let neg_a = I128s12::from_bits(-5_000_000_000_000);
assert_eq!(neg_a.div_floor(b), I128s12::from_bits(-3_000_000_000_000));
let neg_b = I128s12::from_bits(-2_000_000_000_000);
assert_eq!(neg_a.div_floor(neg_b), I128s12::from_bits(2_000_000_000_000));
assert_eq!(a.div_floor(neg_b), I128s12::from_bits(-3_000_000_000_000));
}
#[test]
fn div_ceil_basic() {
let a = I128s12::from_bits(5_000_000_000_000);
let b = I128s12::from_bits(2_000_000_000_000);
assert_eq!(a.div_ceil(b), I128s12::from_bits(3_000_000_000_000));
let neg_a = I128s12::from_bits(-5_000_000_000_000);
assert_eq!(neg_a.div_ceil(b), I128s12::from_bits(-2_000_000_000_000));
let four = I128s12::from_bits(4_000_000_000_000);
assert_eq!(four.div_ceil(b), I128s12::from_bits(2_000_000_000_000));
}
#[test]
fn abs_diff_commutative() {
let a = I128s12::from_bits(5_000_000_000_000); let b = I128s12::from_bits(2_000_000_000_000); let expected = I128s12::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 = I128s12::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 = I128s12::from_bits(1_500_000_000_000);
assert_eq!(x.abs_diff(x), I128s12::ZERO);
assert_eq!(x.abs_diff(I128s12::ZERO), x.abs());
let neg = -x;
assert_eq!(neg.abs_diff(I128s12::ZERO), x);
}
#[test]
fn midpoint_basic() {
let a = I128s12::from_bits(1_000_000_000_000); let b = I128s12::from_bits(3_000_000_000_000); assert_eq!(a.midpoint(b), I128s12::from_bits(2_000_000_000_000));
let neg_a = -a;
let neg_b = -b;
assert_eq!(neg_a.midpoint(neg_b), I128s12::from_bits(-2_000_000_000_000));
assert_eq!(neg_a.midpoint(a), I128s12::ZERO);
}
#[test]
fn midpoint_no_overflow_at_max() {
assert_eq!(I128s12::MAX.midpoint(I128s12::MAX), I128s12::MAX);
assert_eq!(I128s12::MIN.midpoint(I128s12::MIN), I128s12::MIN);
let mid = I128s12::MIN.midpoint(I128s12::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!(!I128s12::ZERO.is_nan());
assert!(!I128s12::ONE.is_nan());
assert!(!I128s12::MAX.is_nan());
assert!(!I128s12::MIN.is_nan());
}
#[test]
fn is_infinite_always_false() {
assert!(!I128s12::ZERO.is_infinite());
assert!(!I128s12::MAX.is_infinite());
assert!(!I128s12::MIN.is_infinite());
}
#[test]
fn is_finite_always_true() {
assert!(I128s12::ZERO.is_finite());
assert!(I128s12::ONE.is_finite());
assert!(I128s12::MAX.is_finite());
assert!(I128s12::MIN.is_finite());
}
#[test]
fn is_normal_zero_is_false() {
assert!(!I128s12::ZERO.is_normal());
}
#[test]
fn is_normal_nonzero_is_true() {
assert!(I128s12::ONE.is_normal());
assert!((-I128s12::ONE).is_normal());
assert!(I128s12::from_bits(1).is_normal()); assert!(I128s12::from_bits(-1).is_normal()); assert!(I128s12::MAX.is_normal());
assert!(I128s12::MIN.is_normal());
}
#[test]
fn is_zero_predicates() {
assert!(I128s12::ZERO.is_zero());
assert!(!I128s12::ZERO.is_positive());
assert!(!I128s12::ZERO.is_negative());
assert!(!I128s12::from_bits(1).is_zero());
assert!(I128s12::from_bits(1).is_positive());
assert!(!I128s12::from_bits(1).is_negative());
assert!(!I128s12::from_bits(-1).is_zero());
assert!(!I128s12::from_bits(-1).is_positive());
assert!(I128s12::from_bits(-1).is_negative());
}
}