Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ceilf16 and ceilf128 #436

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions crates/libm-macros/src/shared.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option<Signature>, &[&str])]
FloatTy::F16,
Signature { args: &[Ty::F16], returns: &[Ty::F16] },
None,
&["fabsf16", "truncf16"],
&["ceilf16", "fabsf16", "truncf16"],
),
(
// `fn(f32) -> f32`
Expand Down Expand Up @@ -40,7 +40,7 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option<Signature>, &[&str])]
FloatTy::F128,
Signature { args: &[Ty::F128], returns: &[Ty::F128] },
None,
&["fabsf128", "truncf128"],
&["ceilf128", "fabsf128", "truncf128"],
),
(
// `(f16, f16) -> f16`
Expand Down
9 changes: 8 additions & 1 deletion crates/libm-test/benches/random.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,14 @@ libm_macros::for_each_function! {
exp10 | exp10f | exp2 | exp2f => (true, Some(musl_math_sys::MACRO_FN_NAME)),

// Musl does not provide `f16` and `f128` functions
copysignf16 | copysignf128 | fabsf16 | fabsf128 | truncf16 | truncf128 => (false, None),
ceilf128
| ceilf16
| copysignf128
| copysignf16
| fabsf128
| fabsf16
| truncf128
| truncf16 => (false, None),

// By default we never skip (false) and always have a musl function available
_ => (false, Some(musl_math_sys::MACRO_FN_NAME))
Expand Down
10 changes: 10 additions & 0 deletions crates/libm-test/src/domain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,16 @@ impl HasDomain<f128> for crate::op::fabsf128::Routine {
const DOMAIN: Domain<f128> = Domain::<f128>::UNBOUNDED;
}

#[cfg(f16_enabled)]
impl HasDomain<f16> for crate::op::ceilf16::Routine {
const DOMAIN: Domain<f16> = Domain::<f16>::UNBOUNDED;
}

#[cfg(f128_enabled)]
impl HasDomain<f128> for crate::op::ceilf128::Routine {
const DOMAIN: Domain<f128> = Domain::<f128>::UNBOUNDED;
}

#[cfg(f16_enabled)]
impl HasDomain<f16> for crate::op::truncf16::Routine {
const DOMAIN: Domain<f16> = Domain::<f16>::UNBOUNDED;
Expand Down
2 changes: 2 additions & 0 deletions crates/libm-test/src/f8_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ impl Float for f8 {
const INFINITY: Self = Self(0b0_1111_000);
const NEG_INFINITY: Self = Self(0b1_1111_000);
const NAN: Self = Self(0b0_1111_100);
// FIXME: incorrect values
const EPSILON: Self = Self::ZERO;
const PI: Self = Self::ZERO;
const NEG_PI: Self = Self::ZERO;
const FRAC_PI_2: Self = Self::ZERO;
Expand Down
4 changes: 4 additions & 0 deletions crates/libm-test/src/mpfloat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,8 @@ libm_macros::for_each_function! {
// Most of these need a manual implementation
ceil,
ceilf,
ceilf128,
ceilf16,
copysign,
copysignf,
copysignf128,
Expand Down Expand Up @@ -237,12 +239,14 @@ impl_no_round! {
#[cfg(f16_enabled)]
impl_no_round! {
fabsf16 => abs_mut;
ceilf16 => ceil_mut;
truncf16 => trunc_mut;
}

#[cfg(f128_enabled)]
impl_no_round! {
fabsf128 => abs_mut;
ceilf128 => ceil_mut;
truncf128 => trunc_mut;
}

Expand Down
17 changes: 14 additions & 3 deletions crates/libm-test/tests/compare_built_musl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,16 @@ where
libm_macros::for_each_function! {
callback: musl_rand_tests,
// Musl does not support `f16` and `f128` on all platforms.
skip: [copysignf16, copysignf128, fabsf16, fabsf128, truncf16, truncf128],
skip: [
ceilf128,
ceilf16,
copysignf128,
copysignf16,
fabsf128,
fabsf16,
truncf128,
truncf16,
],
attributes: [
#[cfg_attr(x86_no_sse, ignore)] // FIXME(correctness): wrong result on i586
[exp10, exp10f, exp2, exp2f, rint]
Expand Down Expand Up @@ -144,9 +153,11 @@ libm_macros::for_each_function! {
ynf,

// Not provided by musl
fabsf16,
ceilf128,
ceilf16,
fabsf128,
truncf16,
fabsf16,
truncf128,
truncf16,
],
}
9 changes: 8 additions & 1 deletion crates/util/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,14 @@ fn do_eval(basis: &str, op: &str, inputs: &[&str]) {
emit_types: [CFn, RustFn, RustArgs],
extra: (basis, op, inputs),
fn_extra: match MACRO_FN_NAME {
copysignf16 | copysignf128 | fabsf16 | fabsf128 | truncf16 | truncf128 => None,
ceilf128
| ceilf16
| copysignf128
| copysignf16
| fabsf128
| fabsf16
| truncf128
| truncf16 => None,
_ => Some(musl_math_sys::MACRO_FN_NAME)
}
}
Expand Down
20 changes: 18 additions & 2 deletions etc/function-definitions.json
Original file line number Diff line number Diff line change
Expand Up @@ -109,17 +109,33 @@
"src/libm_helper.rs",
"src/math/arch/i586.rs",
"src/math/arch/wasm32.rs",
"src/math/ceil.rs"
"src/math/ceil.rs",
"src/math/generic/ceil.rs"
],
"type": "f64"
},
"ceilf": {
"sources": [
"src/math/arch/wasm32.rs",
"src/math/ceilf.rs"
"src/math/ceilf.rs",
"src/math/generic/ceil.rs"
],
"type": "f32"
},
"ceilf128": {
"sources": [
"src/math/ceilf128.rs",
"src/math/generic/ceil.rs"
],
"type": "f128"
},
"ceilf16": {
"sources": [
"src/math/ceilf16.rs",
"src/math/generic/ceil.rs"
],
"type": "f16"
},
"copysign": {
"sources": [
"src/libm_helper.rs",
Expand Down
2 changes: 2 additions & 0 deletions etc/function-list.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ cbrt
cbrtf
ceil
ceilf
ceilf128
ceilf16
copysign
copysignf
copysignf128
Expand Down
42 changes: 1 addition & 41 deletions src/math/ceil.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,3 @@
#![allow(unreachable_code)]
use core::f64;

const TOINT: f64 = 1. / f64::EPSILON;

/// Ceil (f64)
///
/// Finds the nearest integer greater than or equal to `x`.
Expand All @@ -15,40 +10,5 @@ pub fn ceil(x: f64) -> f64 {
args: x,
}

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 {
force_eval!(y);
return if (u >> 63) != 0 { -0. } else { 1. };
}
if y < 0. { x + y + 1. } else { x + y }
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn sanity_check() {
assert_eq!(ceil(1.1), 2.0);
assert_eq!(ceil(2.9), 3.0);
}

/// The spec: https://en.cppreference.com/w/cpp/numeric/math/ceil
#[test]
fn spec_tests() {
// Not Asserted: that the current rounding mode has no effect.
assert!(ceil(f64::NAN).is_nan());
for f in [0.0, -0.0, f64::INFINITY, f64::NEG_INFINITY].iter().copied() {
assert_eq!(ceil(f), f);
}
}
super::generic::ceil(x)
}
51 changes: 1 addition & 50 deletions src/math/ceilf.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
use core::f32;

/// Ceil (f32)
///
/// Finds the nearest integer greater than or equal to `x`.
Expand All @@ -11,52 +9,5 @@ pub fn ceilf(x: f32) -> f32 {
args: x,
}

let mut ui = x.to_bits();
let e = (((ui >> 23) & 0xff).wrapping_sub(0x7f)) as i32;

if e >= 23 {
return x;
}
if e >= 0 {
let m = 0x007fffff >> e;
if (ui & m) == 0 {
return x;
}
force_eval!(x + f32::from_bits(0x7b800000));
if ui >> 31 == 0 {
ui += m;
}
ui &= !m;
} else {
force_eval!(x + f32::from_bits(0x7b800000));
if ui >> 31 != 0 {
return -0.0;
} else if ui << 1 != 0 {
return 1.0;
}
}
f32::from_bits(ui)
}

// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520
#[cfg(not(target_arch = "powerpc64"))]
#[cfg(test)]
mod tests {
use super::*;

#[test]
fn sanity_check() {
assert_eq!(ceilf(1.1), 2.0);
assert_eq!(ceilf(2.9), 3.0);
}

/// The spec: https://en.cppreference.com/w/cpp/numeric/math/ceil
#[test]
fn spec_tests() {
// Not Asserted: that the current rounding mode has no effect.
assert!(ceilf(f32::NAN).is_nan());
for f in [0.0, -0.0, f32::INFINITY, f32::NEG_INFINITY].iter().copied() {
assert_eq!(ceilf(f), f);
}
}
super::generic::ceil(x)
}
7 changes: 7 additions & 0 deletions src/math/ceilf128.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/// Ceil (f128)
///
/// Finds the nearest integer greater than or equal to `x`.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn ceilf128(x: f128) -> f128 {
super::generic::ceil(x)
}
7 changes: 7 additions & 0 deletions src/math/ceilf16.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/// Ceil (f16)
///
/// Finds the nearest integer greater than or equal to `x`.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn ceilf16(x: f16) -> f16 {
super::generic::ceil(x)
}
70 changes: 70 additions & 0 deletions src/math/generic/ceil.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/* SPDX-License-Identifier: MIT
* origin: musl src/math/ceil.c */

use super::super::{CastInto, Float};

pub fn ceil<F: Float>(x: F) -> F {
let toint = F::ONE / F::EPSILON;

// NB: using `exp` here and comparing to values adjusted by `EXP_BIAS` has better
// perf than using `exp_unbiased` here.
let e = x.exp();
let y: F;

// If the represented value has no fractional part, no truncation is needed.
if e >= (F::SIG_BITS + F::EXP_BIAS).cast() || x == F::ZERO {
return x;
}

let neg = x.is_sign_negative();

// y = int(x) - x, where int(x) is an integer neighbor of x.
// The `x - t + t - x` method is a way to expose non-round-to-even modes.
y = if neg { x - toint + toint - x } else { x + toint - toint - x };

// Exp < 0; special case because of non-nearest rounding modes
if e < F::EXP_BIAS.cast() {
// Raise `FE_INEXACT`
force_eval!(y);
return if neg { F::NEG_ZERO } else { F::ONE };
}

if y < F::ZERO { x + y + F::ONE } else { x + y }
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn sanity_check_f64() {
assert_eq!(ceil(1.1f64), 2.0);
assert_eq!(ceil(2.9f64), 3.0);
}

/// The spec: https://en.cppreference.com/w/cpp/numeric/math/ceil
#[test]
fn spec_tests_f64() {
// Not Asserted: that the current rounding mode has no effect.
assert!(ceil(f64::NAN).is_nan());
for f in [0.0, -0.0, f64::INFINITY, f64::NEG_INFINITY].iter().copied() {
assert_eq!(ceil(f), f);
}
}

#[test]
fn sanity_check_f32() {
assert_eq!(ceil(1.1f32), 2.0);
assert_eq!(ceil(2.9f32), 3.0);
}

/// The spec: https://en.cppreference.com/w/cpp/numeric/math/ceil
#[test]
fn spec_tests_f32() {
// Not Asserted: that the current rounding mode has no effect.
assert!(ceil(f32::NAN).is_nan());
for f in [0.0, -0.0, f32::INFINITY, f32::NEG_INFINITY].iter().copied() {
assert_eq!(ceil(f), f);
}
}
}
2 changes: 2 additions & 0 deletions src/math/generic/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
mod ceil;
mod copysign;
mod fabs;
mod trunc;

pub use ceil::ceil;
pub use copysign::copysign;
pub use fabs::fabs;
pub use trunc::trunc;
Loading
Loading