80 lines
2.8 KiB
Rust
80 lines
2.8 KiB
Rust
// 独立 Rust 参照直接使用相同版本的 dec,逐项清理和检查状态。
|
|
// 两侧使用同一输入、Decimal128 精度、舍入和顺序,不用二进制浮点代替。
|
|
|
|
fn generated(values: &[Decimal]) -> Result<Decimal, Fault> {
|
|
GENERATED_DECIMAL_SUM(values)
|
|
}
|
|
|
|
fn reference(values: &[Decimal]) -> Result<Decimal, Fault> {
|
|
let mut context = dec::Context::<dec::Decimal128>::default();
|
|
let mut total = dec::Decimal128::ZERO;
|
|
for value in values {
|
|
context.clear_status();
|
|
total = context.add(total, dec::Decimal128::from_be_bytes(value.to_be_bytes()));
|
|
if !total.is_finite() || context.status().overflow() || context.status().invalid_operation()
|
|
{
|
|
return Err(&FaultInfo {
|
|
message: "Decimal fault",
|
|
source: "Rust reference",
|
|
line: 0,
|
|
column: 0,
|
|
});
|
|
}
|
|
}
|
|
Ok(Decimal::from_be_bytes(total.to_be_bytes()))
|
|
}
|
|
|
|
fn score(value: &Decimal) -> u64 {
|
|
u64::from_be_bytes(value.to_be_bytes()[8..].try_into().unwrap())
|
|
}
|
|
|
|
fn main() {
|
|
let maximum = Decimal::parse("9.999999999999999999999999999999999E+6144").unwrap();
|
|
let zero = Decimal::from_int(0);
|
|
for values in [
|
|
vec![maximum, maximum, -maximum],
|
|
vec![-maximum, -maximum, maximum],
|
|
vec![zero],
|
|
Vec::new(),
|
|
] {
|
|
let actual = generated(&values);
|
|
let expected = reference(&values);
|
|
assert_eq!(actual.is_err(), expected.is_err());
|
|
if let (Ok(actual), Ok(expected)) = (actual, expected) {
|
|
assert_eq!(actual.to_be_bytes(), expected.to_be_bytes());
|
|
}
|
|
}
|
|
let short = [
|
|
"0.1", "0.2", "-0.05", "1.25", "-0.00", "10", "-2.50", "0.001",
|
|
]
|
|
.map(|text| Decimal::parse(text).unwrap());
|
|
let integers = (0..256).map(Decimal::from_int).collect::<Vec<_>>();
|
|
let palette = [
|
|
"-1234567890123456789012345678901234",
|
|
"1.000000000000000000000000000000001",
|
|
"-0.001",
|
|
"-1E-6176",
|
|
"-0.00",
|
|
"0E+100",
|
|
"1E-6176",
|
|
"0.9999999999999999999999999999999999",
|
|
"1234567890123456789012345678901234",
|
|
]
|
|
.map(|text| Decimal::parse(text).unwrap());
|
|
let mixed = (0..256)
|
|
.map(|index| palette[index % palette.len()])
|
|
.collect::<Vec<_>>();
|
|
println!("case,sample,implementation,elapsed_ns,checksum");
|
|
for (name, values, count) in [
|
|
("decimal_sum_short", short.as_slice(), 10000),
|
|
("decimal_sum_integers", integers.as_slice(), 1000),
|
|
("decimal_sum_mixed", mixed.as_slice(), 1000),
|
|
] {
|
|
assert_eq!(
|
|
generated(values).unwrap().to_be_bytes(),
|
|
reference(values).unwrap().to_be_bytes()
|
|
);
|
|
compare(name, values, count, generated, reference, score);
|
|
}
|
|
}
|