Files
IronCalc/base/src/test/statistical/test_fn_t_dist.rs
Nicolás Hatcher 6822505602 UPDATE: Adds 56 functions in the Statistical section
Uses statrs for numerical functions

REFACTOR: Put statistical functions on its own module

This might seem counter-intuitive but the wasm build after this refactor
is 1528 bytes smaller :)
2025-11-25 01:20:03 +01:00

161 lines
4.6 KiB
Rust

#![allow(clippy::unwrap_used)]
use crate::test::util::new_empty_model;
#[test]
fn test_fn_t_dist_smoke() {
let mut model = new_empty_model();
// Valid: cumulative (left-tail CDF)
model._set("A1", "=T.DIST(2, 10, TRUE)");
// Valid: probability density function (PDF)
model._set("B1", "=T.DIST(2, 10, FALSE)");
// Wrong number of arguments
model._set("A2", "=T.DIST(2, 10)");
model._set("A3", "=T.DIST(2, 10, TRUE, FALSE)");
// Domain error: df < 1 -> #NUM!
model._set("A4", "=T.DIST(2, 0, TRUE)");
model._set("A5", "=T.DIST(2, -1, TRUE)");
model.evaluate();
assert_eq!(model._get_text("A1"), *"0.963305983");
assert_eq!(model._get_text("B1"), *"0.061145766");
assert_eq!(model._get_text("A2"), *"#ERROR!");
assert_eq!(model._get_text("A3"), *"#ERROR!");
assert_eq!(model._get_text("A4"), *"#NUM!");
assert_eq!(model._get_text("A5"), *"#NUM!");
}
#[test]
fn test_fn_t_dist_rt_smoke() {
let mut model = new_empty_model();
// Valid: right tail probability
model._set("A1", "=T.DIST.RT(2, 10)");
// Wrong number of arguments
model._set("A2", "=T.DIST.RT(2)");
model._set("A3", "=T.DIST.RT(2, 10, TRUE)");
// Domain error: df < 1
model._set("A4", "=T.DIST.RT(2, 0)");
model._set("A5", "=T.DIST.RT(2, -1)");
model.evaluate();
assert_eq!(model._get_text("A1"), *"0.036694017");
assert_eq!(model._get_text("A2"), *"#ERROR!");
assert_eq!(model._get_text("A3"), *"#ERROR!");
assert_eq!(model._get_text("A4"), *"#NUM!");
assert_eq!(model._get_text("A5"), *"#NUM!");
}
#[test]
fn test_fn_t_dist_2t_smoke() {
let mut model = new_empty_model();
// Valid: two-tailed probability
model._set("A1", "=T.DIST.2T(2, 10)");
// In the limit case of x = 0, the two-tailed probability is 1.0
model._set("A4", "=T.DIST.2T(0, 10)");
// Wrong number of arguments
model._set("A2", "=T.DIST.2T(2)");
model._set("A3", "=T.DIST.2T(2, 10, TRUE)");
// Domain errors:
// x < 0 -> #NUM!
model._set("A5", "=T.DIST.2T(-0.001, 10)");
// df < 1 -> #NUM!
model._set("A6", "=T.DIST.2T(2, 0)");
model.evaluate();
assert_eq!(model._get_text("A1"), *"0.073388035");
assert_eq!(model._get_text("A4"), *"1");
assert_eq!(model._get_text("A2"), *"#ERROR!");
assert_eq!(model._get_text("A3"), *"#ERROR!");
assert_eq!(model._get_text("A5"), *"#NUM!");
assert_eq!(model._get_text("A6"), *"#NUM!");
}
#[test]
fn test_fn_t_inv_smoke() {
let mut model = new_empty_model();
// Valid: upper and lower tail
model._set("A1", "=T.INV(0.95, 10)");
model._set("A2", "=T.INV(0.05, 10)");
// limit case:
model._set("B2", "=T.INV(0.95, 1)");
// Wrong number of arguments
model._set("A3", "=T.INV(0.95)");
model._set("A4", "=T.INV(0.95, 10, 1)");
// Domain errors:
// p <= 0 or >= 1
model._set("A5", "=T.INV(0, 10)");
model._set("A6", "=T.INV(1, 10)");
// df < 1
model._set("A7", "=T.INV(0.95, 0)");
model.evaluate();
assert_eq!(model._get_text("A1"), *"1.812461123");
assert_eq!(model._get_text("A2"), *"-1.812461123");
assert_eq!(model._get_text("B2"), *"6.313751515");
assert_eq!(model._get_text("A3"), *"#ERROR!");
assert_eq!(model._get_text("A4"), *"#ERROR!");
assert_eq!(model._get_text("A5"), *"#NUM!");
assert_eq!(model._get_text("A6"), *"#NUM!");
assert_eq!(model._get_text("A7"), *"#NUM!");
}
#[test]
fn test_fn_t_inv_2t_smoke() {
let mut model = new_empty_model();
// Valid: two-tailed critical values
model._set("A1", "=T.INV.2T(0.1, 10)");
model._set("A2", "=T.INV.2T(0.05, 10)");
// p = 1 should give t = 0 (both tails outside are 1.0, so cut at the mean)
model._set("A3", "=T.INV.2T(1, 10)");
model._set("A7", "=T.INV.2T(1.5, 10)");
// Wrong number of arguments
model._set("A4", "=T.INV.2T(0.1)");
model._set("A5", "=T.INV.2T(0.1, 10, 1)");
// Domain errors:
// p <= 0 or p > 1
model._set("A6", "=T.INV.2T(0, 10)");
// df < 1
model._set("A8", "=T.INV.2T(0.1, 0)");
model.evaluate();
assert_eq!(model._get_text("A1"), *"1.812461123");
assert_eq!(model._get_text("A2"), *"2.228138852");
assert_eq!(model._get_text("A3"), *"0");
// NB: Excel returns -0.699812061 for T.INV.2T(1.5, 10)
// which seems inconsistent with its documented behavior
assert_eq!(model._get_text("A7"), *"#NUM!");
assert_eq!(model._get_text("A4"), *"#ERROR!");
assert_eq!(model._get_text("A5"), *"#ERROR!");
assert_eq!(model._get_text("A6"), *"#NUM!");
assert_eq!(model._get_text("A8"), *"#NUM!");
}