pub(crate) const fn compile_time_max_u16(a: u16, b: u16) -> u16 {
if b < a { a } else { b }
}
#[expect(clippy::many_single_char_names, reason = "It's math, whatyagonnado?")]
pub(crate) const fn compile_time_sqrt(s: f64) -> f64 {
assert!(
s >= 0.0 && s <= 1.0,
"Can only compute square root of numbers between 0 and 1"
);
let mut x = s;
let mut y = 0.0_f64;
let mut z;
let mut i = 0;
while y.to_bits() != x.to_bits() {
y = x;
z = s / y;
x = f64::midpoint(y, z);
i += 1;
}
assert!(i <= 100, "SLOW_SQRT failed to converge");
x
}
#[must_use]
pub(crate) fn ecef2ned_matrix(llh: crate::coords::LLHRadians) -> nalgebra::Matrix3<f64> {
let sin_lat = llh.latitude().sin();
let cos_lat = llh.latitude().cos();
let sin_lon = llh.longitude().sin();
let cos_lon = llh.longitude().cos();
nalgebra::Matrix3::new(
-sin_lat * cos_lon,
-sin_lat * sin_lon,
cos_lat,
-sin_lon,
cos_lon,
0.0,
-cos_lat * cos_lon,
-cos_lat * sin_lon,
-sin_lat,
)
}
#[cfg(test)]
mod tests {
use float_eq::assert_float_eq;
use proptest::prelude::*;
use super::*;
proptest! {
#![proptest_config(ProptestConfig::with_cases(1000))]
#[test]
fn newton_sqrt(x in 0.0..=1.0) {
let newton_approx = compile_time_sqrt(x);
let sqrt = x.sqrt();
assert_float_eq!(sqrt, newton_approx, ulps <= 1, "Newton approximation of square root doesn't match IEEE sqrt! (Newton: {}, IEEE: {})", newton_approx, sqrt);
}
}
}