use dec::{Context, Decimal128, Rounding}; use dever_runtime::number::DecimalValue; use std::hint::black_box; use std::time::Instant; fn finite(context: &Context, value: Decimal128) -> Decimal128 { let status = context.status(); assert!(!status.division_by_zero() && !status.division_undefined()); assert!(!status.overflow() && !status.underflow()); assert!(!status.invalid_operation() && !status.invalid_context() && value.is_finite()); value } fn measure(mode: &str, ticks: &str, initial: &str, factor: &str) -> serde_json::Value { let bytes = black_box(ticks.as_bytes()); let (checksum, elapsed) = if mode == "runtime" { let mut total = DecimalValue::parse(initial).expect("initial"); let factor = DecimalValue::parse(factor).expect("factor"); let begin = Instant::now(); for value in bytes { let product = DecimalValue::from_int(i64::from(*value)) .checked_mul(factor) .expect("multiply"); total = total.checked_add(product).expect("add"); } black_box(total); let elapsed = begin.elapsed(); (total.to_string(), elapsed) } else { assert_eq!(mode, "decimal128"); let mut context = Context::::default(); let mut total = context.parse(initial).expect("initial"); assert!(!context.status().inexact() && total.is_finite()); context.clear_status(); let factor = context.parse(factor).expect("factor"); assert!(!context.status().inexact() && factor.is_finite()); context.set_rounding(Rounding::HalfEven); let begin = Instant::now(); for value in bytes { let item = Decimal128::from(i64::from(*value)); context.clear_status(); let product = context.mul(item, factor); let product = finite(&context, product); context.clear_status(); let sum = context.add(total, product); total = finite(&context, sum); } black_box(total); let elapsed = begin.elapsed(); (context.reduce(total).to_string(), elapsed) }; serde_json::json!({"checksum": checksum, "elapsed_ns": elapsed.as_nanos()}) } fn main() { let arguments = std::env::args().collect::>(); let input: serde_json::Value = serde_json::from_str(&arguments[3]).expect("input object"); let ticks = input["ticks"].as_str().expect("ticks"); let initial = input["initial"].as_str().expect("initial"); let factor = input["factor"].as_str().expect("factor"); let output = match arguments[2].as_str() { "run" => measure(&arguments[1], ticks, initial, factor), "continuous" => serde_json::Value::Array( (0..10) .map(|_| measure(&arguments[1], ticks, initial, factor)) .collect(), ), _ => panic!("unknown measurement"), }; println!("{output}"); }