use std::process::Command;
fn ilo() -> Command {
Command::new(env!("CARGO_BIN_EXE_ilo"))
}
fn run_text(engine: &str, src: &str) -> String {
let out = ilo()
.args([src, engine, "f"])
.output()
.expect("failed to run ilo");
assert!(
out.status.success(),
"ilo {engine} failed for `{src}`: stderr={}",
String::from_utf8_lossy(&out.stderr)
);
String::from_utf8_lossy(&out.stdout).trim().to_string()
}
fn parse_pair(s: &str) -> (f64, f64) {
let parts: Vec<&str> = s.split_whitespace().collect();
assert_eq!(parts.len(), 2, "expected `mean stdev`, got: {s}");
let m: f64 = parts[0].parse().expect("mean not a number");
let d: f64 = parts[1].parse().expect("stdev not a number");
(m, d)
}
fn mc_src(n: i64, mu: f64, sigma: f64) -> String {
format!(
"f>t;s=0;q=0;i=0;wh <i {n}{{x=rndn {mu} {sigma};s=+s x;sq=*x x;q=+q sq;i=+i 1}};m=/s {n};v=/q {n};mm=*m m;vr=-v mm;sd=sqrt vr;a=str m;b=str sd;cat [a,b] \" \""
)
}
fn check_normal_stats(
engine: &str,
n: i64,
mu: f64,
sigma: f64,
mean_tol: f64,
stdev_range: (f64, f64),
) {
let src = mc_src(n, mu, sigma);
let out = run_text(engine, &src);
let (m, d) = parse_pair(&out);
assert!(
(m - mu).abs() < mean_tol,
"engine={engine}: mean {m} not within {mean_tol} of {mu} (out=`{out}`)"
);
assert!(
d >= stdev_range.0 && d <= stdev_range.1,
"engine={engine}: stdev {d} not in {stdev_range:?} (out=`{out}`)"
);
}
const N: i64 = 1000;
#[test]
fn rndn_std_normal_tree() {
check_normal_stats("--vm", N, 0.0, 1.0, 0.2, (0.85, 1.15));
}
#[test]
fn rndn_std_normal_vm() {
check_normal_stats("--vm", N, 0.0, 1.0, 0.2, (0.85, 1.15));
}
#[cfg(feature = "cranelift")]
#[test]
fn rndn_std_normal_cranelift() {
check_normal_stats("--jit", N, 0.0, 1.0, 0.2, (0.85, 1.15));
}
#[test]
fn rndn_shifted_scaled_tree() {
check_normal_stats("--vm", N, 10.0, 2.0, 0.4, (1.7, 2.3));
}
#[test]
fn rndn_shifted_scaled_vm() {
check_normal_stats("--vm", N, 10.0, 2.0, 0.4, (1.7, 2.3));
}
#[cfg(feature = "cranelift")]
#[test]
fn rndn_shifted_scaled_cranelift() {
check_normal_stats("--jit", N, 10.0, 2.0, 0.4, (1.7, 2.3));
}
#[test]
fn rndn_returns_number_type() {
let out = run_text("--vm", "f>n;rndn 0 1");
let v: f64 = out.parse().expect("not a number");
assert!(v.is_finite(), "rndn produced non-finite: {v}");
}
#[test]
fn rndn_zero_sigma_returns_mu() {
let out = run_text("--vm", "f>n;rndn 7 0");
let v: f64 = out.parse().expect("not a number");
assert_eq!(v, 7.0, "rndn 7 0 should be exactly 7, got {v}");
}