use num_traits::Float;
use strafe_type::{FloatConstraint, LogProbability64, Natural64, Probability64, Real64};
use crate::traits::TrigPI;
pub fn qcauchy<P: Into<Probability64>, R: Into<Real64>, N: Into<Natural64>>(
p: P,
location: R,
scale: N,
lower_tail: bool,
) -> Real64 {
let p = p.into().unwrap();
qcauchy_inner(p, location, scale, lower_tail, false)
}
pub fn log_qcauchy<LP: Into<LogProbability64>, R: Into<Real64>, N: Into<Natural64>>(
p: LP,
location: R,
scale: N,
lower_tail: bool,
) -> Real64 {
let p = p.into().unwrap();
qcauchy_inner(p, location, scale, lower_tail, true)
}
fn qcauchy_inner<R: Into<Real64>, N: Into<Natural64>>(
mut p: f64,
location: R,
scale: N,
mut lower_tail: bool,
log: bool,
) -> Real64 {
let location = location.into().unwrap();
let scale = scale.into().unwrap();
if log {
if p > -1.0 {
if p == 0.0 {
return (location + (if lower_tail { scale } else { -scale }) * f64::infinity())
.into();
} lower_tail = !lower_tail; p = -p.exp_m1()
} else {
p = p.exp()
}
} else if p > 0.5 {
if p == 1.0 {
return (location + (if lower_tail { scale } else { -scale }) * f64::infinity()).into();
}
p = 1.0 - p;
lower_tail = !lower_tail
}
if p == 0.5 {
location
} else if p == 0.0 {
location + (if lower_tail { scale } else { -scale }) * f64::NEG_INFINITY
} else {
location + (if lower_tail { -scale } else { scale }) / p.tan_pi()
}
.into()
}