From e3efddc2c25b36408fa5184b6bc8c7700d32b2a4 Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Mon, 7 Nov 2022 12:34:47 -0500 Subject: [PATCH] Add `roundeven` and `roundevenf` --- library/compiler-builtins/libm/build.rs | 3 ++ .../compiler-builtins/libm/src/math/mod.rs | 4 ++ .../libm/src/math/roundeven.rs | 50 +++++++++++++++++++ .../libm/src/math/roundevenf.rs | 50 +++++++++++++++++++ 4 files changed, 107 insertions(+) create mode 100644 library/compiler-builtins/libm/src/math/roundeven.rs create mode 100644 library/compiler-builtins/libm/src/math/roundevenf.rs diff --git a/library/compiler-builtins/libm/build.rs b/library/compiler-builtins/libm/build.rs index 80145a9ccac9..403304a1383b 100644 --- a/library/compiler-builtins/libm/build.rs +++ b/library/compiler-builtins/libm/build.rs @@ -39,6 +39,9 @@ mod musl_reference_tests { "jnf.rs", "j1.rs", "j1f.rs", + // musl doens't have these + "roundeven.rs", + "roundevenf.rs", ]; struct Function { diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 81bfc53ed854..e710bd381bc1 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -171,6 +171,8 @@ mod remainderf; mod remquo; mod remquof; mod round; +mod roundeven; +mod roundevenf; mod roundf; mod scalbn; mod scalbnf; @@ -285,6 +287,8 @@ pub use self::remainderf::remainderf; pub use self::remquo::remquo; pub use self::remquof::remquof; pub use self::round::round; +pub use self::roundeven::roundeven; +pub use self::roundevenf::roundevenf; pub use self::roundf::roundf; pub use self::scalbn::scalbn; pub use self::scalbnf::scalbnf; diff --git a/library/compiler-builtins/libm/src/math/roundeven.rs b/library/compiler-builtins/libm/src/math/roundeven.rs new file mode 100644 index 000000000000..5cc30c8af828 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/roundeven.rs @@ -0,0 +1,50 @@ +// Source: musl libm rint +// (equivalent to roundeven when rounding mode is default, +// which Rust assumes) + +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn roundeven(x: f64) -> f64 { + let one_over_e = 1.0 / f64::EPSILON; + let as_u64: u64 = x.to_bits(); + let exponent: u64 = as_u64 >> 52 & 0x7ff; + let is_positive = (as_u64 >> 63) == 0; + if exponent >= 0x3ff + 52 { + x + } else { + let ans = if is_positive { + x + one_over_e - one_over_e + } else { + x - one_over_e + one_over_e + }; + + if ans == 0.0 { + if is_positive { + 0.0 + } else { + -0.0 + } + } else { + ans + } + } +} + +#[cfg(test)] +mod tests { + use super::roundeven; + + #[test] + fn negative_zero() { + assert_eq!(roundeven(-0.0_f64).to_bits(), (-0.0_f64).to_bits()); + } + + #[test] + fn sanity_check() { + assert_eq!(roundeven(-1.0), -1.0); + assert_eq!(roundeven(2.8), 3.0); + assert_eq!(roundeven(-0.5), -0.0); + assert_eq!(roundeven(0.5), 0.0); + assert_eq!(roundeven(-1.5), -2.0); + assert_eq!(roundeven(1.5), 2.0); + } +} diff --git a/library/compiler-builtins/libm/src/math/roundevenf.rs b/library/compiler-builtins/libm/src/math/roundevenf.rs new file mode 100644 index 000000000000..e720dcd94780 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/roundevenf.rs @@ -0,0 +1,50 @@ +// Source: musl libm rintf +// (equivalent to roundevenf when rounding mode is default, +// which Rust assumes) + +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn roundevenf(x: f32) -> f32 { + let one_over_e = 1.0 / f32::EPSILON; + let as_u32: u32 = x.to_bits(); + let exponent: u32 = as_u32 >> 23 & 0xff; + let is_positive = (as_u32 >> 31) == 0; + if exponent >= 0x7f + 23 { + x + } else { + let ans = if is_positive { + x + one_over_e - one_over_e + } else { + x - one_over_e + one_over_e + }; + + if ans == 0.0 { + if is_positive { + 0.0 + } else { + -0.0 + } + } else { + ans + } + } +} + +#[cfg(test)] +mod tests { + use super::roundevenf; + + #[test] + fn negative_zero() { + assert_eq!(roundevenf(-0.0_f32).to_bits(), (-0.0_f32).to_bits()); + } + + #[test] + fn sanity_check() { + assert_eq!(roundevenf(-1.0), -1.0); + assert_eq!(roundevenf(2.8), 3.0); + assert_eq!(roundevenf(-0.5), -0.0); + assert_eq!(roundevenf(0.5), 0.0); + assert_eq!(roundevenf(-1.5), -2.0); + assert_eq!(roundevenf(1.5), 2.0); + } +}