Files
kickscore/src/utils.rs

89 lines
2.0 KiB
Rust

use std::f64::consts::PI;
const CS: [f64; 14] = [
0.00048204,
-0.00142906,
0.0013200243174,
0.0009461589032,
-0.0045563339802,
0.00556964649138,
0.00125993961762116,
-0.01621575378835404,
0.02629651521057465,
-0.001829764677455021,
2.0 * (1.0 - PI / 3.0),
(4.0 - PI) / 3.0,
1.0,
1.0,
];
const RS: [f64; 5] = [
1.2753666447299659525,
5.019049726784267463450,
6.1602098531096305441,
7.409740605964741794425,
2.9788656263939928886,
];
const QS: [f64; 6] = [
2.260528520767326969592,
9.3960340162350541504,
12.048951927855129036034,
17.081440747466004316,
9.608965327192787870698,
3.3690752069827527677,
];
/// Normal cumulative density function.
fn normcdf(x: f64) -> f64 {
// If X ~ N(0,1), returns P(X < x).
// erfc(-x / SQRT2) / 2.0
// https://docs.rs/statrs/0.12.0/statrs/function/erf/fn.erfc.html
todo!();
}
/// Compute the log of the normal cumulative density function.
pub fn logphi(z: f64) -> (f64, f64) {
// Adapted from the GPML function `logphi.m`.
let SQRT2: f64 = 2.0f64.sqrt();
let SQRT2PI: f64 = (2.0 * PI).sqrt();
if z * z < 0.0492 {
// First case: z close to zero.
let coef = -z / SQRT2PI;
let mut val = 0.0;
for c in &CS {
val = coef * (c + val);
}
let res = -2.0 * val - 2.0f64.ln();
let dres = (-(z * z) / 2.0 - res).exp() / SQRT2PI;
(res, dres)
} else if z < -11.3137 {
// Second case: z very small.
let mut num = 0.5641895835477550741;
for r in &RS {
num = -z * num / SQRT2 + r;
}
let mut den = 1.0;
for q in &QS {
den = -z * den / SQRT2 + q;
}
let res = (num / (2.0 * den)).ln() - (z * z) / 2.0;
let dres = (den / num).abs() * (2.0 / PI).sqrt();
(res, dres)
} else {
let res = normcdf(z).ln();
let dres = (-(z * z) / 2.0 - res).exp() / SQRT2PI;
(res, dres)
}
}