use strafe_type::{FloatConstraint, LogProbability64, Probability64, Rational64, Real64};
use crate::{
distribution::{
beta::{log_pbeta, pbeta},
norm::{log_pnorm, pnorm},
},
func::lbeta,
traits::DPQ,
};
pub fn pt<RE: Into<Real64>, RA: Into<Rational64>>(
x: RE,
n: RA,
mut lower_tail: bool,
) -> Probability64 {
let x = x.into().unwrap();
let n = n.into().unwrap();
let mut val = 0.0;
let mut nx = 0.0;
if !x.is_finite() {
return if x < 0.0 {
f64::dt_0(lower_tail, false)
} else {
f64::dt_1(lower_tail, false)
}
.into();
}
if !n.is_finite() {
return pnorm(x, 0.0, 1.0, lower_tail);
}
nx = 1.0 + x / n * x;
if nx > 1e100 {
let mut lval = 0.0_f64;
lval = -0.5 * n * (2.0 * x.abs().ln() - n.ln())
- lbeta(0.5 * n, 0.5).unwrap()
- (0.5 * n).ln();
val = lval.exp();
} else {
val = if n > x * x {
pbeta(x * x / (n + x * x), 0.5, n / 2.0, false)
} else {
pbeta(1.0 / nx, n / 2.0, 0.5, true)
}
.unwrap()
}
if x <= 0.0 {
lower_tail = !lower_tail
}
val /= 2.0;
val = val.d_cval(lower_tail);
val.into()
}
pub fn log_pt<RE: Into<Real64>, RA: Into<Rational64>>(
x: RE,
n: RA,
mut lower_tail: bool,
) -> LogProbability64 {
let x = x.into().unwrap();
let n = n.into().unwrap();
let mut val = 0.0;
let mut nx = 0.0;
if !x.is_finite() {
return if x < 0.0 {
f64::dt_0(lower_tail, true)
} else {
f64::dt_1(lower_tail, true)
}
.into();
}
if !n.is_finite() {
return log_pnorm(x, 0.0, 1.0, lower_tail);
}
nx = 1.0 + x / n * x;
if nx > 1e100 {
let mut lval = 0.0;
lval = -0.5 * n * (2.0 * x.abs().ln() - n.ln())
- lbeta(0.5 * n, 0.5).unwrap()
- (0.5 * n).ln();
val = lval;
} else {
val = if n > x * x {
log_pbeta(x * x / (n + x * x), 0.5, n / 2.0, false)
} else {
log_pbeta(1.0 / nx, n / 2.0, 0.5, true)
}
.unwrap()
}
if x <= 0.0 {
lower_tail = !lower_tail
}
if lower_tail {
(-0.5 * val.exp()).ln_1p()
} else {
val - std::f64::consts::LN_2
}
.into()
}