use crate::traits::{Float, Int as _};
pub(crate) fn ceil<F: Float>(x: F) -> F {
let e = x.raw_exp();
if e < F::EXP_OFFSET {
if !x.sign() && (x.to_raw() & (F::EXP_MASK | F::MANT_MASK)) != F::Raw::ZERO {
F::one()
} else {
F::ZERO.copysign(x)
}
} else {
let fmask = F::MANT_MASK >> (e - F::EXP_OFFSET).min(F::RawExp::from(F::MANT_BITS));
let xraw = x.to_raw();
let fpart = xraw & fmask;
let ipart = xraw & !fmask;
if !x.sign() && fpart != F::Raw::ZERO {
F::from_raw(ipart + fmask + F::Raw::ONE)
} else {
F::from_raw(ipart)
}
}
}
#[cfg(test)]
mod tests {
use crate::traits::Float;
use crate::FloatMath;
fn test<F: Float + FloatMath>() {
use crate::ceil;
let one = F::one();
let pt_1 = F::parse("0.1");
let pt_5 = F::parse("0.5");
let pt_9 = F::parse("0.9");
assert_is_nan!(ceil(F::NAN));
assert_total_eq!(ceil(F::INFINITY), F::INFINITY);
assert_total_eq!(ceil(F::neg_infinity()), F::neg_infinity());
for i in 0..20u32 {
let x = F::cast_from(i);
assert_total_eq!(ceil(x), x);
assert_total_eq!(ceil(-x), -x);
assert_total_eq!(ceil(x + pt_1), x + one);
assert_total_eq!(ceil(-(x + pt_1)), -x);
assert_total_eq!(ceil(x + pt_5), x + one);
assert_total_eq!(ceil(-(x + pt_5)), -x);
assert_total_eq!(ceil(x + pt_9), x + one);
assert_total_eq!(ceil(-(x + pt_9)), -x);
}
}
#[test]
fn test_f32() {
test::<f32>();
}
#[cfg(feature = "soft-float")]
#[test]
fn test_soft_f32() {
test::<crate::SoftF32>();
}
#[test]
fn test_f64() {
test::<f64>();
}
#[cfg(feature = "soft-float")]
#[test]
fn test_soft_f64() {
test::<crate::SoftF64>();
}
}