//! 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()); }