use crate::consts::{M_HALFPI, M_PI, M_TWOPI};
const ONE_TOL: f64 = 1.00000000000001;
const ATOL: f64 = 1e-50;
pub fn aasin(v: f64) -> f64 {
let av = v.abs();
if av >= 1.0 {
let _out_of_domain = av > ONE_TOL;
if v < 0.0 {
-M_HALFPI
} else {
M_HALFPI
}
} else {
v.asin()
}
}
pub fn aacos(v: f64) -> f64 {
if v.abs() >= 1.0 {
if v < 0.0 {
M_PI
} else {
0.0
}
} else {
v.acos()
}
}
pub fn asqrt(v: f64) -> f64 {
if v <= 0.0 {
0.0
} else {
v.sqrt()
}
}
pub fn aatan2(n: f64, d: f64) -> f64 {
if n.abs() < ATOL && d.abs() < ATOL {
0.0
} else {
n.atan2(d)
}
}
pub fn adjlon(mut longitude: f64) -> f64 {
if longitude.abs() < M_PI + 1e-12 {
return longitude;
}
longitude += M_PI;
longitude -= M_TWOPI * (longitude / M_TWOPI).floor();
longitude -= M_PI;
longitude
}
#[cfg(test)]
mod tests {
use super::*;
use crate::consts::{M_HALFPI, M_PI, M_TWOPI};
#[test]
fn adjlon_reduces_above_range() {
assert!((adjlon(M_TWOPI + 1.0) - 1.0).abs() < 1e-9);
}
#[test]
fn adjlon_reduces_below_range() {
assert!((adjlon(-M_TWOPI - 1.0) - (-1.0)).abs() < 1e-9);
}
#[test]
fn adjlon_passes_small_angle_unchanged() {
assert!(adjlon(0.5) == 0.5);
}
#[test]
fn aasin_clamps_positive_out_of_domain() {
assert!((aasin(2.0) - M_HALFPI).abs() < 1e-12);
}
#[test]
fn aasin_clamps_negative_out_of_domain() {
assert!((aasin(-2.0) - (-M_HALFPI)).abs() < 1e-12);
}
#[test]
fn aasin_in_domain_matches_std() {
assert!((aasin(0.5) - 0.5_f64.asin()).abs() < 1e-12);
}
#[test]
fn aacos_clamps_positive_out_of_domain() {
assert!(aacos(2.0) == 0.0);
}
#[test]
fn aacos_clamps_negative_out_of_domain() {
assert!((aacos(-2.0) - M_PI).abs() < 1e-12);
}
#[test]
fn aacos_in_domain_matches_std() {
assert!((aacos(0.5) - 0.5_f64.acos()).abs() < 1e-12);
}
#[test]
fn asqrt_negative_is_zero() {
assert!(asqrt(-1.0) == 0.0);
}
#[test]
fn asqrt_positive_matches_std() {
assert!(asqrt(4.0) == 2.0);
}
#[test]
fn aatan2_both_zero_is_zero() {
assert!(aatan2(0.0, 0.0) == 0.0);
}
#[test]
fn aatan2_nonzero_matches_std() {
assert!((aatan2(1.0, 1.0) - 1.0_f64.atan2(1.0)).abs() < 1e-12);
}
}