inv-chisquare-cdf
Version:
Inverse chi-squared cumulative distribution function
69 lines (63 loc) • 2.04 kB
JavaScript
const logGamma = require('./logGamma.js');
const regLowGamma = require('./regLowGamma.js');
module.exports = function invRegLowGamma(p, a) {
if (isNaN(p)) {
// TODO fix: booleans and strings like '123' will not fall here.
throw new Error('The value in param "p" is not an number.');
} else if (isNaN(a)) {
// TODO fix: booleans and strings like '123' will not fall here.
throw new Error('The value in param "a" is not an number.');
} else if (p >= 1) {
return Math.max(100, a + 100 * Math.sqrt(a));
} else if (p <= 0) {
return 0;
}
const a1 = a - 1;
const EPS = 1e-8;
const gln = logGamma(a);
let inverseRegLowGamma;
let err;
let t;
let u;
let pp;
let lna1;
let afac;
if (a > 1) {
lna1 = Math.log(a1);
afac = Math.exp(a1 * (lna1 - 1) - gln);
pp = (p < 0.5) ? p : 1 - p;
t = Math.sqrt(-2 * Math.log(pp));
inverseRegLowGamma = (2.30753 + t * 0.27061) / (1 + t * (0.99229 + t * 0.04481)) - t;
if (p < 0.5) {
inverseRegLowGamma = -inverseRegLowGamma;
}
inverseRegLowGamma = Math.max(1e-3, a * Math.pow(1 - 1 / (9 * a) - inverseRegLowGamma / (3 * Math.sqrt(a)), 3));
} else {
t = 1 - a * (0.253 + a * 0.12);
if (p < t) {
inverseRegLowGamma = Math.pow(p / t, 1 / a);
} else {
inverseRegLowGamma = 1 - Math.log(1 - (p - t) / (1 - t));
}
}
for (let j = 0; j < 12; j++) {
if (inverseRegLowGamma <= 0) {
return 0;
}
err = regLowGamma(a, inverseRegLowGamma) - p;
if (a > 1) {
t = afac * Math.exp(-(inverseRegLowGamma - a1) + a1 * (Math.log(inverseRegLowGamma) - lna1));
} else {
t = Math.exp(-inverseRegLowGamma + a1 * Math.log(inverseRegLowGamma) - gln);
}
u = err / t;
inverseRegLowGamma -= (t = u / (1 - 0.5 * Math.min(1, u * ((a - 1) / inverseRegLowGamma - 1))));
if (inverseRegLowGamma <= 0) {
inverseRegLowGamma = 0.5 * (inverseRegLowGamma + t);
}
if (Math.abs(t) < EPS * inverseRegLowGamma) {
break;
}
}
return inverseRegLowGamma;
};