Files
endorphin-aster-vm/crates/objects/tests/arithmetic.rs
T

70 lines
3.1 KiB
Rust

//! number.rs 的公开 API 回归:比较数学值与存储表示分开,且构造/运算使用不同预算。
use objects::{ArithmeticOp, CompareOp, EndorNumber, EndorReal};
/// 测试辅助:用 numeric_compare 断言数学相等,不能用 Rust Eq 比较不同表示。
fn equal(a: &EndorNumber, b: &EndorNumber) {
assert!(a.numeric_compare(b, CompareOp::Eq).unwrap());
}
#[test]
/// 测试框架调用:验证精确跨表示求和、整数溢出提升、有理数等价和大整数混合浮点比较。
fn exact_real_arithmetic_keeps_large_values_and_cross_representation_equivalence() {
// 十进制保留尾零,后续与分数求和应保持精确数学值。
let tenth = EndorNumber::decimal("0.10").unwrap();
// 分数构造不要求约分,算术结果仍应等价于精确 0.3。
let fifth = EndorNumber::rational("2", "10").unwrap();
equal(
&tenth.arithmetic(&fifth, ArithmeticOp::Add).unwrap(),
&EndorNumber::decimal("0.3").unwrap(),
);
// 机器最大整数加一必须提升到大整数,不能溢出或丢精度。
let large = EndorNumber::integer("9223372036854775807").unwrap();
equal(
&large.arithmetic(&1_i64.into(), ArithmeticOp::Add).unwrap(),
&EndorNumber::integer("9223372036854775808").unwrap(),
);
// 最小负整数转换需单独处理其超出正 i64 范围的幅值。
let min = EndorNumber::integer("-9223372036854775808").unwrap();
assert_eq!(min.as_i64(), Some(i64::MIN));
equal(
&min.negated().unwrap(),
&EndorNumber::integer("9223372036854775808").unwrap(),
);
equal(
&EndorNumber::rational("2", "6").unwrap(),
&EndorNumber::rational("1", "3").unwrap(),
);
assert!(
EndorNumber::integer("9007199254740993")
.unwrap()
.numeric_compare(&EndorNumber::binary_float(9007199254740992.), CompareOp::Gt)
.unwrap()
);
}
#[test]
/// 测试框架调用:验证 IEEE 符号零/NaN、零除/非有限结果拒绝,以及巨大指数可存不可运算。
fn ieee_signed_zero_nan_and_operation_limits_are_explicit() {
// 浮点取负翻符号位,+0 应变 -0 而不是规范成整数零。
let negative = EndorNumber::binary_float(0.).negated().unwrap();
assert_eq!(
negative.as_real(),
Some(&EndorReal::BinaryFloat((-0.0_f64).to_bits()))
);
// 同一 NaN 数学比较也不等于自身,Ne 必须为真。
let nan = EndorNumber::binary_float(f64::NAN);
assert!(!nan.numeric_compare(&nan, CompareOp::Eq).unwrap());
assert!(nan.numeric_compare(&nan, CompareOp::Ne).unwrap());
assert!(
EndorNumber::from(1_i64)
.arithmetic(&0_i64.into(), ArithmeticOp::Divide)
.is_err()
);
assert!(
EndorNumber::binary_float(f64::MAX)
.arithmetic(&2_i64.into(), ArithmeticOp::Multiply)
.is_err()
);
// 极长指数语法合法且可原样显示,但实际运算要触发预算保护。
let huge = EndorNumber::decimal("1e99999999999999999").unwrap();
assert_eq!(huge.to_string(), "1e99999999999999999");
assert!(huge.arithmetic(&1_i64.into(), ArithmeticOp::Add).is_err());
}