use nalgebra::RealField;
pub fn unit_d_ball_vol<X: RealField + Copy>(d: usize) -> X {
let one = X::one();
let two = one + one;
let radius = one;
let mut volumes = vec![one, two * radius];
while volumes.len() <= d {
let n = volumes.len();
let n_ = X::from_subset(&(n as f64));
let next = (two * X::pi() / n_) * radius.powi(2) * volumes[n - 2];
volumes.push(next);
}
volumes[d]
}
pub fn atan2<X: RealField + Copy>(y: X, x: X) -> Option<X> {
match (x, y) {
(x, y) if x > X::zero() => Some(X::atan(y / x)),
(x, y) if x < X::zero() && y >= X::zero() => Some(X::atan(y / x) + X::pi()),
(x, y) if x < X::zero() && y < X::zero() => Some(X::atan(y / x) - X::pi()),
(x, y) if x == X::zero() && y > X::zero() => Some(X::frac_pi_2()),
(x, y) if x == X::zero() && y < X::zero() => Some(-X::frac_pi_2()),
_ => None,
}
}
#[cfg(test)]
mod tests {
use std::f32::consts as f32c;
use std::f64::consts as f64c;
use super::*;
fn rel_eq<X: RealField + Copy>(a: X, b: X) -> bool {
let abs_difference = (a - b).abs();
abs_difference < X::from_subset(&10.0).powi(-5)
}
#[test]
fn test_unit_d_ball_vol_f32() {
assert!(rel_eq(unit_d_ball_vol::<f32>(1), 2.));
assert!(rel_eq(unit_d_ball_vol::<f32>(2), f32c::PI));
assert!(rel_eq(unit_d_ball_vol::<f32>(3), f32c::PI * (4. / 3.)));
assert!(rel_eq(
unit_d_ball_vol::<f32>(4),
f32c::PI.powi(2) * (1. / 2.)
));
assert!(rel_eq(
unit_d_ball_vol::<f32>(5),
f32c::PI.powi(2) * (8. / 15.)
));
assert!(rel_eq(
unit_d_ball_vol::<f32>(6),
f32c::PI.powi(3) * (1. / 6.)
));
assert!(rel_eq(
unit_d_ball_vol::<f32>(7),
f32c::PI.powi(3) * (16. / 105.)
));
assert!(rel_eq(
unit_d_ball_vol::<f32>(8),
f32c::PI.powi(4) * (1. / 24.)
));
}
#[test]
fn test_unit_d_ball_vol_f64() {
assert!(rel_eq(unit_d_ball_vol::<f64>(1), 2.));
assert!(rel_eq(unit_d_ball_vol::<f64>(2), f64c::PI));
assert!(rel_eq(unit_d_ball_vol::<f64>(3), f64c::PI * (4. / 3.)));
assert!(rel_eq(
unit_d_ball_vol::<f64>(4),
f64c::PI.powi(2) * (1. / 2.)
));
assert!(rel_eq(
unit_d_ball_vol::<f64>(5),
f64c::PI.powi(2) * (8. / 15.)
));
assert!(rel_eq(
unit_d_ball_vol::<f64>(6),
f64c::PI.powi(3) * (1. / 6.)
));
assert!(rel_eq(
unit_d_ball_vol::<f64>(7),
f64c::PI.powi(3) * (16. / 105.)
));
assert!(rel_eq(
unit_d_ball_vol::<f64>(8),
f64c::PI.powi(4) * (1. / 24.)
));
}
}