diff --git a/src/lib.rs b/src/lib.rs index 22734c1..9095fd8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -347,7 +347,6 @@ impl F32Ext for f32 { pub trait F64Ext: private::Sealed { fn floor(self) -> Self; - #[cfg(todo)] fn ceil(self) -> Self; fn round(self) -> Self; @@ -455,7 +454,6 @@ impl F64Ext for f64 { floor(self) } - #[cfg(todo)] #[inline] fn ceil(self) -> Self { ceil(self) diff --git a/src/math/ceil.rs b/src/math/ceil.rs new file mode 100644 index 0000000..4db2ca8 --- /dev/null +++ b/src/math/ceil.rs @@ -0,0 +1,39 @@ +use core::f64; + +const TOINT: f64 = 1. / f64::EPSILON; + +#[inline] +pub fn ceil(x: f64) -> f64 { + let u: u64 = x.to_bits(); + let e: i64 = (u >> 52 & 0x7ff) as i64; + let y: f64; + + if e >= 0x3ff + 52 || x == 0. { + return x; + } + // y = int(x) - x, where int(x) is an integer neighbor of x + y = if (u >> 63) != 0 { + x - TOINT + TOINT - x + } else { + x + TOINT - TOINT - x + }; + // special case because of non-nearest rounding modes + if e <= 0x3ff - 1 { + force_eval!(y); + return if (u >> 63) != 0 { -0. } else { 1. }; + } + if y < 0. { + x + y + 1. + } else { + x + y + } +} + +#[cfg(test)] +mod tests { + #[test] + fn sanity_check() { + assert_eq!(super::ceil(1.1), 2.0); + assert_eq!(super::ceil(2.9), 3.0); + } +} diff --git a/src/math/mod.rs b/src/math/mod.rs index 34309d5..ee846eb 100644 --- a/src/math/mod.rs +++ b/src/math/mod.rs @@ -6,6 +6,7 @@ macro_rules! force_eval { }; } +mod ceil; mod ceilf; mod cosf; mod expf; @@ -35,6 +36,7 @@ mod trunc; mod truncf; // Use separated imports instead of {}-grouped imports for easier merging. +pub use self::ceil::ceil; pub use self::ceilf::ceilf; pub use self::cosf::cosf; pub use self::expf::expf; diff --git a/test-generator/src/main.rs b/test-generator/src/main.rs index f876aea..291c30f 100644 --- a/test-generator/src/main.rs +++ b/test-generator/src/main.rs @@ -700,7 +700,7 @@ f64_f64! { // asin, // atan, // cbrt, - // ceil, + ceil, // cos, // cosh, // exp,