use uninum::{Number, num};
#[test]
fn test_basic_remainder() {
assert_eq!(Number::from(17u64) % Number::from(5u64), Number::from(2u64));
assert_eq!(
Number::from(-17i64) % Number::from(5i64),
Number::from(-2i64)
);
assert_eq!(
Number::from(17i64) % Number::from(-5i64),
Number::from(2i64)
);
assert_eq!(
Number::from(-17i64) % Number::from(-5i64),
Number::from(-2i64)
);
assert_eq!(Number::from(31u64) % Number::from(3u64), Number::from(1u64));
let a = num!(17.5);
let b = num!(5.0);
assert_eq!(&a % &b, num!(2.5));
assert_eq!(Number::from(17u64) % num!(5.0), num!(2.0));
}
#[test]
fn test_remainder_with_primitives() {
let num = Number::from(10u64);
assert_eq!(&num % 3, Number::from(1u64));
assert_eq!(33 % &num, Number::from(3u64));
assert_eq!(&num % 3u32, Number::from(1u64));
assert_eq!(&num % 4i32, Number::from(2u64));
assert_eq!(&num % 3.0f64, num!(1.0));
}
#[test]
fn test_remainder_reference_semantics() {
let a = Number::from(17u64);
let b = Number::from(5u64);
assert_eq!(&a % &b, Number::from(2u64));
assert_eq!(&a % b.clone(), Number::from(2u64));
assert_eq!(a.clone() % &b, Number::from(2u64));
assert_eq!(a.clone() % b.clone(), Number::from(2u64));
assert_eq!(a, Number::from(17u64));
assert_eq!(b, Number::from(5u64));
}
#[test]
fn test_remainder_by_zero() {
assert!((Number::from(10u64) % Number::from(0u64)).is_nan());
assert!((Number::from(-10i64) % Number::from(0i64)).is_nan());
assert!((num!(10.0) % num!(0.0)).is_nan());
}
#[test]
fn test_remainder_special_floats() {
let inf = num!(f64::INFINITY);
let neg_inf = num!(f64::NEG_INFINITY);
let nan = num!(f64::NAN);
let normal = Number::from(42u64);
let result = &inf % &normal;
assert!(result.is_nan());
let result = &neg_inf % &normal;
assert!(result.is_nan());
let result = &nan % &normal;
assert!(result.is_nan());
let result = &normal % &inf;
assert_eq!(result, Number::from(42u64));
let result = &normal % &neg_inf;
assert_eq!(result, Number::from(42u64));
let result = &normal % &nan;
assert!(result.is_nan());
assert!((num!(f64::NAN) % num!(5.0)).is_nan());
assert!((num!(10.0) % num!(f64::NAN)).is_nan());
assert!((num!(f64::INFINITY) % num!(5.0)).is_nan());
assert!((num!(f64::NEG_INFINITY) % num!(5.0)).is_nan());
}
#[test]
fn test_remainder_exact() {
assert_eq!(Number::from(20u64) % Number::from(4u64), Number::from(0u64));
assert_eq!(
Number::from(100u64) % Number::from(10u64),
Number::from(0u64)
);
assert_eq!(
Number::from(-20i64) % Number::from(4i64),
Number::from(0i64)
);
assert_eq!(num!(20.0) % num!(4.0), num!(0.0));
assert_eq!(
Number::from(100u64) % Number::from(1u64),
Number::from(0u64)
);
assert_eq!(
Number::from(-100i64) % Number::from(1i64),
Number::from(0i64)
);
assert_eq!(
Number::from(100i64) % Number::from(-1i64),
Number::from(0i64)
);
assert_eq!(
Number::from(-100i64) % Number::from(-1i64),
Number::from(0i64)
);
assert_eq!(
Number::from(42u64) % Number::from(42u64),
Number::from(0u64)
);
assert_eq!(
num!(std::f64::consts::PI) % num!(std::f64::consts::PI),
num!(0.0)
);
let result = num!(std::f64::consts::PI) % num!(1.0);
let expected = num!(std::f64::consts::PI % 1.0);
if let (Some(r), Some(e)) = (result.try_get_f64(), expected.try_get_f64()) {
assert!((r - e).abs() < 1e-10);
} else {
#[cfg(feature = "decimal")]
{
if result.try_get_decimal().is_none() {
panic!("Expected F64 or Decimal results");
}
}
#[cfg(not(feature = "decimal"))]
{
panic!("Expected F64 result");
}
}
}
#[test]
fn test_remainder_chains() {
let result = Number::from(100u64) % Number::from(30u64) % Number::from(7u64);
assert_eq!(result, Number::from(3u64));
let result = Number::from(100u64) % Number::from(30u64) % num!(6.0);
assert_eq!(result, num!(4.0));
let result =
((Number::from(100u64) % Number::from(30u64)) % Number::from(7u64)) % Number::from(3u64);
assert_eq!(result, Number::from(0u64));
let result = ((Number::from(1000000u64) % Number::from(1000u64)) % Number::from(100i64))
% Number::from(10u64);
assert_eq!(result, Number::from(0u64)); }
#[test]
fn test_small_type_remainder() {
let a = Number::from(100u64);
let b = Number::from(30u64);
assert_eq!(&a % &b, Number::from(10u64));
let c = Number::from(-100i64);
let d = Number::from(30i64);
assert_eq!(&c % &d, Number::from(-10i64));
assert_eq!(
Number::from(100u64) % Number::from(30u64),
Number::from(10u64)
);
assert_eq!(
Number::from(-100i64) % Number::from(30i64),
Number::from(-10i64)
);
}
#[cfg(feature = "decimal")]
#[test]
fn test_remainder_with_decimal() {
use rust_decimal::Decimal;
let a = Number::from(Decimal::new(17, 0));
let b = Number::from(Decimal::new(5, 0));
let result = &a % &b;
assert!(result.try_get_decimal().is_some());
if let Some(d) = result.try_get_decimal() {
assert_eq!(**d, Decimal::new(2, 0));
}
let zero = Number::from(Decimal::ZERO);
let result = &a % &zero;
assert!(result.is_nan());
let c = Number::from(Decimal::new(175, 1)); let d = Number::from(Decimal::new(50, 1)); let result = &c % &d;
assert!(result.try_get_decimal().is_some());
if let Some(d) = result.try_get_decimal() {
assert_eq!(d.to_string(), "2.5");
}
}
#[test]
fn test_negative_remainder_edge_cases() {
assert_eq!(Number::from(7i64) % Number::from(3i64), Number::from(1i64));
assert_eq!(Number::from(7i64) % Number::from(-3i64), Number::from(1i64));
assert_eq!(
Number::from(-7i64) % Number::from(3i64),
Number::from(-1i64)
);
assert_eq!(
Number::from(-7i64) % Number::from(-3i64),
Number::from(-1i64)
);
let min_i32 = Number::from(i64::from(i32::MIN));
let neg_one = Number::from(-1i64);
let result = &min_i32 % &neg_one;
assert_eq!(result, Number::from(0i64)); }
#[test]
fn test_integer_overflow_cases() {
assert_eq!(
Number::from(i64::from(i32::MIN)) % Number::from(-1i64),
Number::from(0i64)
);
assert_eq!(
Number::from(i64::MIN) % Number::from(-1i64),
Number::from(0i64)
);
let min_i32 = Number::from(i64::from(i32::MIN));
let neg_one = Number::from(-1i64);
assert_eq!(&min_i32 % &neg_one, Number::from(0i64));
}
#[test]
fn test_remainder_large_numbers() {
let large = Number::from(u64::MAX - 1);
let divisor = Number::from(100u64);
let result = &large % &divisor;
assert!(result.try_get_u64().is_some());
let a = Number::from(1000000001u64);
let b = Number::from(1000000000u64);
assert_eq!(&a % &b, Number::from(1u64));
let large = Number::from(u64::MAX);
let small = Number::from(10u64);
let result = large % small;
assert_eq!(result, Number::from(5u64));
let result = num!(1e10) % num!(3.0);
if let Some(r) = result.try_get_f64() {
assert!((r - 1.0).abs() < 1e-10);
} else {
#[cfg(feature = "decimal")]
{
if result.try_get_decimal().is_none() {
panic!("Expected F64 or Decimal result");
}
}
#[cfg(not(feature = "decimal"))]
{
panic!("Expected F64 result");
}
}
}
#[test]
fn test_float_remainder_precision() {
let a = num!(10.3);
let b = num!(3.1);
let result = &a % &b;
#[cfg(feature = "decimal")]
assert!(result.try_get_f64().is_some() || result.try_get_decimal().is_some());
#[cfg(not(feature = "decimal"))]
assert!(result.try_get_f64().is_some());
if let Some(f) = result.try_get_f64() {
assert!((f - 1.0).abs() < 1e-10);
}
let c = num!(1.0);
let d = num!(0.3);
let result = &c % &d;
#[cfg(feature = "decimal")]
assert!(result.try_get_f64().is_some() || result.try_get_decimal().is_some());
#[cfg(not(feature = "decimal"))]
assert!(result.try_get_f64().is_some());
if let Some(f) = result.try_get_f64() {
assert!((f - 0.1).abs() < 1e-10);
}
}
#[test]
fn test_all_type_combinations() {
let u32_val = Number::from(17u64);
let i32_val = Number::from(-17i64);
let u64_val = Number::from(17u64);
let i64_val = Number::from(-17i64);
let f64_val = num!(17.5);
assert_eq!(&u32_val % Number::from(5i64), Number::from(2i64));
assert_eq!(&u64_val % Number::from(5i64), Number::from(2i64));
assert_eq!(&i32_val % Number::from(5u64), Number::from(-2i64));
assert_eq!(&i64_val % Number::from(5u64), Number::from(-2i64));
assert_eq!(&i32_val % &f64_val, num!(-17.0));
assert_eq!(&f64_val % Number::from(5i64), num!(2.5));
}
#[test]
fn test_extended_primitive_combinations() {
let num = Number::from(17u64);
assert_eq!(&num % 5u32, Number::from(2u64));
assert_eq!(&num % 5u64, Number::from(2u64));
#[cfg(feature = "decimal")]
{
use rust_decimal::Decimal;
let result = &num % 5usize;
if let Some(d) = result.try_get_decimal() {
assert_eq!(**d, Decimal::new(2, 0));
}
}
#[cfg(not(feature = "decimal"))]
assert_eq!(&num % 5usize, Number::from(2u64));
assert_eq!(&num % 5i32, Number::from(2u64));
assert_eq!(&num % 5i64, Number::from(2i64));
#[cfg(feature = "decimal")]
{
use rust_decimal::Decimal;
let result = &num % 5isize;
if let Some(d) = result.try_get_decimal() {
assert_eq!(**d, Decimal::new(2, 0));
}
}
#[cfg(not(feature = "decimal"))]
assert_eq!(&num % 5isize, Number::from(2i64));
assert_eq!(&num % 5.0f64, num!(2.0));
assert_eq!(33u32 % &num, Number::from(16u64));
assert_eq!(33u64 % &num, Number::from(16u64));
assert_eq!(33i32 % &num, Number::from(16u64));
assert_eq!(-33i32 % &num, Number::from(-16i64));
assert_eq!(33.5f64 % &num, num!(16.5));
#[cfg(feature = "decimal")]
{
use rust_decimal::Decimal;
let result = 33usize % #
if let Some(d) = result.try_get_decimal() {
assert_eq!(**d, Decimal::new(16, 0));
}
let result = 33isize % #
if let Some(d) = result.try_get_decimal() {
assert_eq!(**d, Decimal::new(16, 0));
}
}
#[cfg(not(feature = "decimal"))]
{
assert_eq!(33usize % &num, Number::from(16u64));
assert_eq!(33isize % &num, Number::from(16i64));
}
}
#[test]
fn test_usize_isize_remainder() {
let num = Number::from(100u64);
#[cfg(feature = "decimal")]
{
use rust_decimal::Decimal;
let result = &num % 30usize;
if let Some(d) = result.try_get_decimal() {
assert_eq!(**d, Decimal::new(10, 0));
} else if let Some(n) = result.try_get_u64() {
assert_eq!(n, 10);
} else {
panic!("Unexpected result type: {result:?}");
}
let result = &num % 30isize;
if let Some(d) = result.try_get_decimal() {
assert_eq!(**d, Decimal::new(10, 0));
} else if let Some(n) = result.try_get_u64() {
assert_eq!(n, 10);
} else {
panic!("Unexpected result type: {result:?}");
}
}
#[cfg(not(feature = "decimal"))]
{
assert_eq!(&num % 30usize, Number::from(10u64));
assert_eq!(&num % 30isize, Number::from(10i64));
}
let divisor = Number::from(30u64);
#[cfg(feature = "decimal")]
{
use rust_decimal::Decimal;
let result = 100usize % &divisor;
if let Some(d) = result.try_get_decimal() {
assert_eq!(**d, Decimal::new(10, 0));
} else if let Some(n) = result.try_get_u64() {
assert_eq!(n, 10);
} else {
panic!("Unexpected result type: {result:?}");
}
let result = 100isize % &divisor;
if let Some(d) = result.try_get_decimal() {
assert_eq!(**d, Decimal::new(10, 0));
} else if let Some(n) = result.try_get_i64() {
assert_eq!(n, 10);
} else {
panic!("Unexpected result type: {result:?}");
}
let result = -100isize % &divisor;
if let Some(d) = result.try_get_decimal() {
assert_eq!(**d, Decimal::new(-10, 0));
} else if let Some(n) = result.try_get_i64() {
assert_eq!(n, -10);
} else {
panic!("Unexpected result type: {result:?}");
}
}
#[cfg(not(feature = "decimal"))]
{
assert_eq!(100usize % &divisor, Number::from(10u64));
assert_eq!(100isize % &divisor, Number::from(10i64));
assert_eq!(-100isize % &divisor, Number::from(-10i64));
}
let large_usize = usize::MAX / 2;
let result = large_usize % Number::from(1000u64);
#[cfg(feature = "decimal")]
assert!(result.try_get_u64().is_some() || result.try_get_decimal().is_some());
#[cfg(not(feature = "decimal"))]
assert!(result.try_get_u64().is_some());
let large_isize = isize::MAX / 2;
let result = large_isize % Number::from(1000i64);
#[cfg(feature = "decimal")]
assert!(result.try_get_i64().is_some() || result.try_get_decimal().is_some());
#[cfg(not(feature = "decimal"))]
assert!(result.try_get_i64().is_some());
}
#[test]
fn test_remainder_type_consistency() {
let divisor = 7;
assert_eq!(
Number::from(17u64) % Number::from(u64::from(divisor as u32)),
Number::from(3u64)
);
assert_eq!(
Number::from(17u64) % Number::from(divisor as u64),
Number::from(3u64)
);
assert_eq!(
Number::from(17i64) % Number::from(i64::from(divisor)),
Number::from(3i64)
);
assert_eq!(
Number::from(17i64) % Number::from(divisor as i64),
Number::from(3i64)
);
assert_eq!(num!(17.0) % num!(divisor as f64), num!(3.0));
}
#[test]
fn test_remainder_with_pow() {
let result = Number::from(2u64).pow(&Number::from(5u64)) % Number::from(7u64);
assert_eq!(result, Number::from(4u64));
let result = Number::from(3u64).pow(&Number::from(10u64)) % Number::from(100u64);
assert_eq!(result, Number::from(49u64));
let result = Number::from(-2i64).pow(&Number::from(5u64)) % Number::from(7i64);
assert_eq!(result, Number::from(-4i64));
let result = (Number::from(17u64) % Number::from(5u64)).pow(&Number::from(3u64));
assert_eq!(result, Number::from(8u64));
let result = (Number::from(-17i64) % Number::from(5i64)).pow(&Number::from(2u64));
assert_eq!(result, Number::from(4i64));
}
#[test]
fn test_usize_isize_platform_independence() {
let usize_num = Number::from(42usize);
assert_eq!(usize_num.try_get_u64(), Some(42));
let isize_num = Number::from(-42isize);
assert_eq!(isize_num.try_get_i64(), Some(-42));
let usize_max = Number::from(usize::MAX);
assert!(usize_max.try_get_u64().is_some());
if let Some(val) = usize_max.try_get_u64() {
assert_eq!(val, usize::MAX as u64);
}
let isize_max = Number::from(isize::MAX);
assert!(isize_max.try_get_i64().is_some());
if let Some(val) = isize_max.try_get_i64() {
assert_eq!(val, isize::MAX as i64);
}
let isize_min = Number::from(isize::MIN);
assert!(isize_min.try_get_i64().is_some());
if let Some(val) = isize_min.try_get_i64() {
assert_eq!(val, isize::MIN as i64);
}
}
#[test]
fn test_remainder_by_zero_all_types() {
assert!((Number::from(10u64) % Number::from(0u64)).is_nan());
assert!((Number::from(10u64) % Number::from(0u64)).is_nan());
assert!((Number::from(10i64) % Number::from(0i64)).is_nan());
assert!((Number::from(10i64) % Number::from(0i64)).is_nan());
assert!((num!(10.0) % num!(0.0)).is_nan());
}