pub fn abs(x: f64) -> f64 {
if x < 0.0 {
-x
} else {
x
}
}
pub fn trunc(x: f64) -> f64 {
if !x.is_finite() {
return x;
}
if abs(x) >= 4_503_599_627_370_496.0 {
return x;
}
(x as i64) as f64
}
pub fn floor(x: f64) -> f64 {
let t = trunc(x);
if t > x {
t - 1.0
} else {
t
}
}
pub fn round(x: f64) -> f64 {
if !x.is_finite() {
return x;
}
let bump = if x < 0.0 { -0.5 } else { 0.5 };
trunc(x + bump)
}
pub fn fmod(x: f64, y: f64) -> f64 {
if y == 0.0 || !x.is_finite() {
return f64::NAN;
}
x - trunc(x / y) * y
}
pub fn powi(base: f64, exp: i32) -> f64 {
if exp < 0 {
return 1.0 / powi(base, -exp);
}
let mut acc = 1.0;
let mut b = base;
let mut e = exp as u32;
while e > 0 {
if e & 1 == 1 {
acc *= b;
}
b *= b;
e >>= 1;
}
acc
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn basics() {
assert_eq!(abs(-3.5), 3.5);
assert_eq!(trunc(3.9), 3.0);
assert_eq!(trunc(-3.9), -3.0);
assert_eq!(floor(-3.1), -4.0);
assert_eq!(round(2.5), 3.0);
assert_eq!(round(-2.5), -3.0);
assert_eq!(round(2.4), 2.0);
assert_eq!(powi(10.0, 3), 1000.0);
assert_eq!(powi(2.0, 10), 1024.0);
assert_eq!(fmod(7.5, 2.0), 1.5);
}
}