204 lines
5.1 KiB
Rust
204 lines
5.1 KiB
Rust
// 保留直接 Rust 参照,分别观察值参数、借用参数和 Result 对循环优化的影响。
|
|
|
|
fn generated(values: &[Option<f64>]) -> Result<i64, Fault> {
|
|
let mut total = 0i64;
|
|
for value in values {
|
|
total += GENERATED_FLOAT(value)?;
|
|
}
|
|
Ok(total)
|
|
}
|
|
|
|
fn reference(values: &[Option<f64>]) -> Result<i64, Fault> {
|
|
let mut total = 0i64;
|
|
for value in values {
|
|
total += match value {
|
|
None => -1,
|
|
Some(value) if *value == 1.0 => 1,
|
|
Some(value) if *value == 0.0 => 0,
|
|
Some(_) => 2,
|
|
};
|
|
}
|
|
Ok(total)
|
|
}
|
|
|
|
fn generated_batch(values: &[Option<f64>]) -> Result<i64, Fault> {
|
|
GENERATED_FLOAT_TOTAL(values)
|
|
}
|
|
|
|
fn reference_batch(values: &[Option<f64>]) -> Result<i64, Fault> {
|
|
let mut total = 0i64;
|
|
for value in values {
|
|
let projected = match value {
|
|
None => -1,
|
|
Some(value) if *value == 1.0 => 1,
|
|
Some(value) if *value == 0.0 => 0,
|
|
Some(_) => 2,
|
|
};
|
|
total = total.checked_add(projected).ok_or(&FaultInfo {
|
|
message: "integer overflow",
|
|
source: "Rust reference",
|
|
line: 0,
|
|
column: 0,
|
|
})?;
|
|
}
|
|
Ok(total)
|
|
}
|
|
|
|
fn classify(value: Option<f64>) -> i64 {
|
|
match value {
|
|
None => -1,
|
|
Some(value) if value == 1.0 => 1,
|
|
Some(value) if value == 0.0 => 0,
|
|
Some(_) => 2,
|
|
}
|
|
}
|
|
|
|
fn classify_result(value: Option<f64>) -> Result<i64, Fault> {
|
|
Ok(classify(value))
|
|
}
|
|
|
|
fn classify_borrowed(value: &Option<f64>) -> i64 {
|
|
match value {
|
|
None => -1,
|
|
Some(value) if *value == 1.0 => 1,
|
|
Some(value) if *value == 0.0 => 0,
|
|
Some(_) => 2,
|
|
}
|
|
}
|
|
|
|
fn value_helper(values: &[Option<f64>]) -> Result<i64, Fault> {
|
|
let mut total = 0i64;
|
|
for value in values {
|
|
total += classify(*value);
|
|
}
|
|
Ok(total)
|
|
}
|
|
|
|
fn result_helper(values: &[Option<f64>]) -> Result<i64, Fault> {
|
|
let mut total = 0i64;
|
|
for value in values {
|
|
total += classify_result(*value)?;
|
|
}
|
|
Ok(total)
|
|
}
|
|
|
|
fn borrowed_helper(values: &[Option<f64>]) -> Result<i64, Fault> {
|
|
let mut total = 0i64;
|
|
for value in values {
|
|
total += classify_borrowed(value);
|
|
}
|
|
Ok(total)
|
|
}
|
|
|
|
fn main() {
|
|
let special = [
|
|
None,
|
|
Some(0.0),
|
|
Some(-0.0),
|
|
Some(1.0),
|
|
Some(-1.0),
|
|
Some(f64::NAN),
|
|
Some(f64::INFINITY),
|
|
Some(f64::NEG_INFINITY),
|
|
];
|
|
let values = (0..256)
|
|
.map(|index| special[index % special.len()])
|
|
.collect::<Vec<_>>();
|
|
let mut state = 0x123456789abcdef0u64;
|
|
let mixed = (0..256)
|
|
.map(|index| {
|
|
state = state.wrapping_mul(6364136223846793005).wrapping_add(1);
|
|
if index % 3 == 0 {
|
|
Some(f64::from_bits(state))
|
|
} else {
|
|
special[((state >> 32) as usize) % special.len()]
|
|
}
|
|
})
|
|
.collect::<Vec<_>>();
|
|
let references = [
|
|
(
|
|
"direct",
|
|
reference as fn(&[Option<f64>]) -> Result<i64, Fault>,
|
|
),
|
|
("value", value_helper),
|
|
("result", result_helper),
|
|
("borrowed", borrowed_helper),
|
|
];
|
|
for (name, operation) in references {
|
|
for value in values.iter().chain(&mixed) {
|
|
assert_eq!(generated(&[*value]).unwrap(), operation(&[*value]).unwrap());
|
|
}
|
|
eprintln!(
|
|
"{name}_equals_generated={}",
|
|
std::ptr::fn_addr_eq(
|
|
operation,
|
|
generated as fn(&[Option<f64>]) -> Result<i64, Fault>
|
|
)
|
|
);
|
|
}
|
|
println!("case,sample,implementation,elapsed_ns,checksum");
|
|
for (name, values) in [("float_batch", &values), ("float_batch_mixed", &mixed)] {
|
|
compare(
|
|
name,
|
|
values,
|
|
10000,
|
|
generated_batch,
|
|
reference_batch,
|
|
|value| *value as u64,
|
|
);
|
|
}
|
|
compare(
|
|
"float_direct",
|
|
&values,
|
|
10000,
|
|
generated,
|
|
reference,
|
|
|value| *value as u64,
|
|
);
|
|
compare(
|
|
"float_mixed",
|
|
&mixed,
|
|
10000,
|
|
generated,
|
|
reference,
|
|
|value| *value as u64,
|
|
);
|
|
compare(
|
|
"float_value_helper",
|
|
&values,
|
|
10000,
|
|
generated,
|
|
value_helper,
|
|
|value| *value as u64,
|
|
);
|
|
compare(
|
|
"float_result_helper",
|
|
&values,
|
|
10000,
|
|
generated,
|
|
result_helper,
|
|
|value| *value as u64,
|
|
);
|
|
compare(
|
|
"float_borrowed_helper",
|
|
&values,
|
|
10000,
|
|
generated,
|
|
borrowed_helper,
|
|
|value| *value as u64,
|
|
);
|
|
// 同一混合序列也经过各参照,避免把函数边界或布局差异归给 Dever。
|
|
for (name, operation) in [
|
|
(
|
|
"float_mixed_value_helper",
|
|
value_helper as fn(&[Option<f64>]) -> Result<i64, Fault>,
|
|
),
|
|
("float_mixed_result_helper", result_helper),
|
|
("float_mixed_borrowed_helper", borrowed_helper),
|
|
] {
|
|
compare(name, &mixed, 10000, generated, operation, |value| {
|
|
*value as u64
|
|
});
|
|
}
|
|
}
|