Add roundeven{,f,f16,f128}
C23 specifies a new set of `roundeven` functions that round to the nearest integral, with ties to even. It does not raise any floating point exceptions. This behavior is similar to two other functions: 1. `rint`, which rounds to the nearest integer respecting rounding mode and possibly raising exceptions. 2. `nearbyint`, which is identical to `rint` except it may not raise exceptions. Technically `rint`, `nearbyint`, and `roundeven` all behave the same in Rust because we assume default floating point environment. The backends are allowed to lower to `roundeven`, however, so we should provide it in case the fallback is needed. Add the `roundeven` family here and convert `rint` to a function that takes a rounding mode. This currently has no effect.
This commit is contained in:
parent
2a3ef8b9a2
commit
53a055049c
20 changed files with 364 additions and 102 deletions
|
|
@ -9,7 +9,16 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option<Signature>, &[&str])]
|
|||
FloatTy::F16,
|
||||
Signature { args: &[Ty::F16], returns: &[Ty::F16] },
|
||||
None,
|
||||
&["ceilf16", "fabsf16", "floorf16", "rintf16", "roundf16", "sqrtf16", "truncf16"],
|
||||
&[
|
||||
"ceilf16",
|
||||
"fabsf16",
|
||||
"floorf16",
|
||||
"rintf16",
|
||||
"roundevenf16",
|
||||
"roundf16",
|
||||
"sqrtf16",
|
||||
"truncf16",
|
||||
],
|
||||
),
|
||||
(
|
||||
// `fn(f32) -> f32`
|
||||
|
|
@ -17,10 +26,43 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option<Signature>, &[&str])]
|
|||
Signature { args: &[Ty::F32], returns: &[Ty::F32] },
|
||||
None,
|
||||
&[
|
||||
"acosf", "acoshf", "asinf", "asinhf", "atanf", "atanhf", "cbrtf", "ceilf", "cosf",
|
||||
"coshf", "erfcf", "erff", "exp10f", "exp2f", "expf", "expm1f", "fabsf", "floorf",
|
||||
"j0f", "j1f", "lgammaf", "log10f", "log1pf", "log2f", "logf", "rintf", "roundf",
|
||||
"sinf", "sinhf", "sqrtf", "tanf", "tanhf", "tgammaf", "truncf", "y0f", "y1f",
|
||||
"acosf",
|
||||
"acoshf",
|
||||
"asinf",
|
||||
"asinhf",
|
||||
"atanf",
|
||||
"atanhf",
|
||||
"cbrtf",
|
||||
"ceilf",
|
||||
"cosf",
|
||||
"coshf",
|
||||
"erfcf",
|
||||
"erff",
|
||||
"exp10f",
|
||||
"exp2f",
|
||||
"expf",
|
||||
"expm1f",
|
||||
"fabsf",
|
||||
"floorf",
|
||||
"j0f",
|
||||
"j1f",
|
||||
"lgammaf",
|
||||
"log10f",
|
||||
"log1pf",
|
||||
"log2f",
|
||||
"logf",
|
||||
"rintf",
|
||||
"roundevenf",
|
||||
"roundf",
|
||||
"sinf",
|
||||
"sinhf",
|
||||
"sqrtf",
|
||||
"tanf",
|
||||
"tanhf",
|
||||
"tgammaf",
|
||||
"truncf",
|
||||
"y0f",
|
||||
"y1f",
|
||||
],
|
||||
),
|
||||
(
|
||||
|
|
@ -29,10 +71,43 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option<Signature>, &[&str])]
|
|||
Signature { args: &[Ty::F64], returns: &[Ty::F64] },
|
||||
None,
|
||||
&[
|
||||
"acos", "acosh", "asin", "asinh", "atan", "atanh", "cbrt", "ceil", "cos", "cosh",
|
||||
"erf", "erfc", "exp", "exp10", "exp2", "expm1", "fabs", "floor", "j0", "j1", "lgamma",
|
||||
"log", "log10", "log1p", "log2", "rint", "round", "sin", "sinh", "sqrt", "tan", "tanh",
|
||||
"tgamma", "trunc", "y0", "y1",
|
||||
"acos",
|
||||
"acosh",
|
||||
"asin",
|
||||
"asinh",
|
||||
"atan",
|
||||
"atanh",
|
||||
"cbrt",
|
||||
"ceil",
|
||||
"cos",
|
||||
"cosh",
|
||||
"erf",
|
||||
"erfc",
|
||||
"exp",
|
||||
"exp10",
|
||||
"exp2",
|
||||
"expm1",
|
||||
"fabs",
|
||||
"floor",
|
||||
"j0",
|
||||
"j1",
|
||||
"lgamma",
|
||||
"log",
|
||||
"log10",
|
||||
"log1p",
|
||||
"log2",
|
||||
"rint",
|
||||
"round",
|
||||
"roundeven",
|
||||
"sin",
|
||||
"sinh",
|
||||
"sqrt",
|
||||
"tan",
|
||||
"tanh",
|
||||
"tgamma",
|
||||
"trunc",
|
||||
"y0",
|
||||
"y1",
|
||||
],
|
||||
),
|
||||
(
|
||||
|
|
@ -40,7 +115,16 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option<Signature>, &[&str])]
|
|||
FloatTy::F128,
|
||||
Signature { args: &[Ty::F128], returns: &[Ty::F128] },
|
||||
None,
|
||||
&["ceilf128", "fabsf128", "floorf128", "rintf128", "roundf128", "sqrtf128", "truncf128"],
|
||||
&[
|
||||
"ceilf128",
|
||||
"fabsf128",
|
||||
"floorf128",
|
||||
"rintf128",
|
||||
"roundevenf128",
|
||||
"roundf128",
|
||||
"sqrtf128",
|
||||
"truncf128",
|
||||
],
|
||||
),
|
||||
(
|
||||
// `(f16, f16) -> f16`
|
||||
|
|
|
|||
|
|
@ -274,6 +274,10 @@ main!(
|
|||
icount_bench_rintf16_group,
|
||||
icount_bench_rintf_group,
|
||||
icount_bench_round_group,
|
||||
icount_bench_roundeven_group,
|
||||
icount_bench_roundevenf128_group,
|
||||
icount_bench_roundevenf16_group,
|
||||
icount_bench_roundevenf_group,
|
||||
icount_bench_roundf128_group,
|
||||
icount_bench_roundf16_group,
|
||||
icount_bench_roundf_group,
|
||||
|
|
|
|||
|
|
@ -154,6 +154,10 @@ libm_macros::for_each_function! {
|
|||
| ldexpf16
|
||||
| rintf128
|
||||
| rintf16
|
||||
| roundeven
|
||||
| roundevenf
|
||||
| roundevenf128
|
||||
| roundevenf16
|
||||
| roundf128
|
||||
| roundf16
|
||||
| scalbnf128
|
||||
|
|
|
|||
|
|
@ -246,6 +246,7 @@ pub fn get_domain<F: Float, I: Int>(
|
|||
BaseName::Remquo => &EitherPrim::UNBOUNDED2[..],
|
||||
BaseName::Rint => &EitherPrim::UNBOUNDED1[..],
|
||||
BaseName::Round => &EitherPrim::UNBOUNDED1[..],
|
||||
BaseName::Roundeven => &EitherPrim::UNBOUNDED1[..],
|
||||
BaseName::Scalbn => &EitherPrim::UNBOUNDED_F_I[..],
|
||||
BaseName::Sin => &EitherPrim::TRIG[..],
|
||||
BaseName::Sincos => &EitherPrim::TRIG[..],
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
//!
|
||||
//! This is useful for adding regression tests or expected failures.
|
||||
|
||||
use libm::hf64;
|
||||
#[cfg(f128_enabled)]
|
||||
use libm::hf128;
|
||||
|
||||
|
|
@ -574,7 +575,15 @@ fn remquof_cases() -> Vec<TestCase<op::remquof::Routine>> {
|
|||
}
|
||||
|
||||
fn rint_cases() -> Vec<TestCase<op::rint::Routine>> {
|
||||
vec![]
|
||||
let mut v = vec![];
|
||||
TestCase::append_pairs(
|
||||
&mut v,
|
||||
&[
|
||||
// Failure on i586
|
||||
((hf64!("-0x1.e3f13ff995ffcp+38"),), Some(hf64!("-0x1.e3f13ff994000p+38"))),
|
||||
],
|
||||
);
|
||||
v
|
||||
}
|
||||
|
||||
fn rintf_cases() -> Vec<TestCase<op::rintf::Routine>> {
|
||||
|
|
@ -591,6 +600,11 @@ fn rintf16_cases() -> Vec<TestCase<op::rintf16::Routine>> {
|
|||
vec![]
|
||||
}
|
||||
|
||||
#[cfg(f16_enabled)]
|
||||
fn roundf16_cases() -> Vec<TestCase<op::roundf16::Routine>> {
|
||||
vec![]
|
||||
}
|
||||
|
||||
fn round_cases() -> Vec<TestCase<op::round::Routine>> {
|
||||
vec![]
|
||||
}
|
||||
|
|
@ -605,7 +619,28 @@ fn roundf128_cases() -> Vec<TestCase<op::roundf128::Routine>> {
|
|||
}
|
||||
|
||||
#[cfg(f16_enabled)]
|
||||
fn roundf16_cases() -> Vec<TestCase<op::roundf16::Routine>> {
|
||||
fn roundevenf16_cases() -> Vec<TestCase<op::roundevenf16::Routine>> {
|
||||
vec![]
|
||||
}
|
||||
|
||||
fn roundeven_cases() -> Vec<TestCase<op::roundeven::Routine>> {
|
||||
let mut v = vec![];
|
||||
TestCase::append_pairs(
|
||||
&mut v,
|
||||
&[
|
||||
// Failure on i586
|
||||
((hf64!("-0x1.e3f13ff995ffcp+38"),), Some(hf64!("-0x1.e3f13ff994000p+38"))),
|
||||
],
|
||||
);
|
||||
v
|
||||
}
|
||||
|
||||
fn roundevenf_cases() -> Vec<TestCase<op::roundevenf::Routine>> {
|
||||
vec![]
|
||||
}
|
||||
|
||||
#[cfg(f128_enabled)]
|
||||
fn roundevenf128_cases() -> Vec<TestCase<op::roundevenf128::Routine>> {
|
||||
vec![]
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -184,6 +184,10 @@ libm_macros::for_each_function! {
|
|||
rintf128,
|
||||
rintf16,
|
||||
round,
|
||||
roundeven,
|
||||
roundevenf,
|
||||
roundevenf128,
|
||||
roundevenf16,
|
||||
roundf,
|
||||
roundf128,
|
||||
roundf16,
|
||||
|
|
@ -253,6 +257,8 @@ impl_no_round! {
|
|||
rint => round_even_mut; // FIXME: respect rounding mode
|
||||
rintf => round_even_mut; // FIXME: respect rounding mode
|
||||
round => round_mut;
|
||||
roundeven => round_even_mut;
|
||||
roundevenf => round_even_mut;
|
||||
roundf => round_mut;
|
||||
trunc => trunc_mut;
|
||||
truncf => trunc_mut;
|
||||
|
|
@ -265,6 +271,7 @@ impl_no_round! {
|
|||
floorf16 => floor_mut;
|
||||
rintf16 => round_even_mut; // FIXME: respect rounding mode
|
||||
roundf16 => round_mut;
|
||||
roundevenf16 => round_even_mut;
|
||||
truncf16 => trunc_mut;
|
||||
}
|
||||
|
||||
|
|
@ -275,6 +282,7 @@ impl_no_round! {
|
|||
floorf128 => floor_mut;
|
||||
rintf128 => round_even_mut; // FIXME: respect rounding mode
|
||||
roundf128 => round_mut;
|
||||
roundevenf128 => round_even_mut;
|
||||
truncf128 => trunc_mut;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ pub fn default_ulp(ctx: &CheckCtx) -> u32 {
|
|||
| Bn::Remquo
|
||||
| Bn::Rint
|
||||
| Bn::Round
|
||||
| Bn::Roundeven
|
||||
| Bn::Scalbn
|
||||
| Bn::Sqrt
|
||||
| Bn::Trunc => 0,
|
||||
|
|
@ -282,7 +283,7 @@ impl MaybeOverride<(f64,)> for SpecialCase {
|
|||
}
|
||||
|
||||
if cfg!(x86_no_sse)
|
||||
&& ctx.base_name == BaseName::Rint
|
||||
&& (ctx.base_name == BaseName::Rint || ctx.base_name == BaseName::Roundeven)
|
||||
&& (expected - actual).abs() <= F::ONE
|
||||
&& (expected - actual).abs() > F::ZERO
|
||||
{
|
||||
|
|
|
|||
|
|
@ -126,6 +126,10 @@ libm_macros::for_each_function! {
|
|||
ldexpf16,
|
||||
rintf128,
|
||||
rintf16,
|
||||
roundeven,
|
||||
roundevenf,
|
||||
roundevenf128,
|
||||
roundevenf16,
|
||||
roundf128,
|
||||
roundf16,
|
||||
scalbnf128,
|
||||
|
|
|
|||
|
|
@ -123,6 +123,10 @@ fn do_eval(basis: &str, op: &str, inputs: &[&str]) {
|
|||
| ldexpf16
|
||||
| rintf128
|
||||
| rintf16
|
||||
| roundeven
|
||||
| roundevenf
|
||||
| roundevenf128
|
||||
| roundevenf16
|
||||
| roundf128
|
||||
| roundf16
|
||||
| scalbnf128
|
||||
|
|
|
|||
|
|
@ -791,7 +791,6 @@
|
|||
"sources": [
|
||||
"src/math/arch/aarch64.rs",
|
||||
"src/math/arch/wasm32.rs",
|
||||
"src/math/generic/rint.rs",
|
||||
"src/math/rint.rs"
|
||||
],
|
||||
"type": "f64"
|
||||
|
|
@ -800,22 +799,19 @@
|
|||
"sources": [
|
||||
"src/math/arch/aarch64.rs",
|
||||
"src/math/arch/wasm32.rs",
|
||||
"src/math/generic/rint.rs",
|
||||
"src/math/rintf.rs"
|
||||
"src/math/rint.rs"
|
||||
],
|
||||
"type": "f32"
|
||||
},
|
||||
"rintf128": {
|
||||
"sources": [
|
||||
"src/math/generic/rint.rs",
|
||||
"src/math/rintf128.rs"
|
||||
"src/math/rint.rs"
|
||||
],
|
||||
"type": "f128"
|
||||
},
|
||||
"rintf16": {
|
||||
"sources": [
|
||||
"src/math/generic/rint.rs",
|
||||
"src/math/rintf16.rs"
|
||||
"src/math/rint.rs"
|
||||
],
|
||||
"type": "f16"
|
||||
},
|
||||
|
|
@ -826,6 +822,30 @@
|
|||
],
|
||||
"type": "f64"
|
||||
},
|
||||
"roundeven": {
|
||||
"sources": [
|
||||
"src/math/roundeven.rs"
|
||||
],
|
||||
"type": "f64"
|
||||
},
|
||||
"roundevenf": {
|
||||
"sources": [
|
||||
"src/math/roundeven.rs"
|
||||
],
|
||||
"type": "f32"
|
||||
},
|
||||
"roundevenf128": {
|
||||
"sources": [
|
||||
"src/math/roundeven.rs"
|
||||
],
|
||||
"type": "f128"
|
||||
},
|
||||
"roundevenf16": {
|
||||
"sources": [
|
||||
"src/math/roundeven.rs"
|
||||
],
|
||||
"type": "f16"
|
||||
},
|
||||
"roundf": {
|
||||
"sources": [
|
||||
"src/math/generic/round.rs",
|
||||
|
|
|
|||
|
|
@ -125,6 +125,10 @@ rintf
|
|||
rintf128
|
||||
rintf16
|
||||
round
|
||||
roundeven
|
||||
roundevenf
|
||||
roundevenf128
|
||||
roundevenf16
|
||||
roundf
|
||||
roundf128
|
||||
roundf16
|
||||
|
|
|
|||
|
|
@ -94,6 +94,7 @@ libm_helper! {
|
|||
(fn remquo(x: f32, y: f32) -> (f32, i32); => remquof);
|
||||
(fn rint(x: f32) -> (f32); => rintf);
|
||||
(fn round(x: f32) -> (f32); => roundf);
|
||||
(fn roundeven(x: f32) -> (f32); => roundevenf);
|
||||
(fn scalbn(x: f32, n: i32) -> (f32); => scalbnf);
|
||||
(fn sin(x: f32) -> (f32); => sinf);
|
||||
(fn sincos(x: f32) -> (f32, f32); => sincosf);
|
||||
|
|
@ -167,6 +168,7 @@ libm_helper! {
|
|||
(fn remquo(x: f64, y: f64) -> (f64, i32); => remquo);
|
||||
(fn rint(x: f64) -> (f64); => rint);
|
||||
(fn round(x: f64) -> (f64); => round);
|
||||
(fn roundevem(x: f64) -> (f64); => roundeven);
|
||||
(fn scalbn(x: f64, n: i32) -> (f64); => scalbn);
|
||||
(fn sin(x: f64) -> (f64); => sin);
|
||||
(fn sincos(x: f64) -> (f64, f64); => sincos);
|
||||
|
|
@ -188,22 +190,23 @@ libm_helper! {
|
|||
f16,
|
||||
funcs: {
|
||||
// verify-sorted-start
|
||||
(fn ceilf(x: f16) -> (f16); => ceilf16);
|
||||
(fn ceil(x: f16) -> (f16); => ceilf16);
|
||||
(fn copysign(x: f16, y: f16) -> (f16); => copysignf16);
|
||||
(fn fabs(x: f16) -> (f16); => fabsf16);
|
||||
(fn fdim(x: f16, y: f16) -> (f16); => fdimf16);
|
||||
(fn floorf(x: f16) -> (f16); => floorf16);
|
||||
(fn fmaxf(x: f16, y: f16) -> (f16); => fmaxf16);
|
||||
(fn fmaximum_numf16(x: f16, y: f16) -> (f16); => fmaximum_numf16);
|
||||
(fn floor(x: f16) -> (f16); => floorf16);
|
||||
(fn fmax(x: f16, y: f16) -> (f16); => fmaxf16);
|
||||
(fn fmaximum_num(x: f16, y: f16) -> (f16); => fmaximum_numf16);
|
||||
(fn fmaximumf16(x: f16, y: f16) -> (f16); => fmaximumf16);
|
||||
(fn fminf(x: f16, y: f16) -> (f16); => fminf16);
|
||||
(fn fminimum_numf16(x: f16, y: f16) -> (f16); => fminimum_numf16);
|
||||
(fn fminimumf16(x: f16, y: f16) -> (f16); => fminimumf16);
|
||||
(fn fmodf(x: f16, y: f16) -> (f16); => fmodf16);
|
||||
(fn ldexpf16(x: f16, n: i32) -> (f16); => ldexpf16);
|
||||
(fn rintf(x: f16) -> (f16); => rintf16);
|
||||
(fn roundf(x: f16) -> (f16); => roundf16);
|
||||
(fn scalbnf16(x: f16, n: i32) -> (f16); => ldexpf16);
|
||||
(fn fmin(x: f16, y: f16) -> (f16); => fminf16);
|
||||
(fn fminimum(x: f16, y: f16) -> (f16); => fminimumf16);
|
||||
(fn fminimum_num(x: f16, y: f16) -> (f16); => fminimum_numf16);
|
||||
(fn fmod(x: f16, y: f16) -> (f16); => fmodf16);
|
||||
(fn ldexp(x: f16, n: i32) -> (f16); => ldexpf16);
|
||||
(fn rint(x: f16) -> (f16); => rintf16);
|
||||
(fn round(x: f16) -> (f16); => roundf16);
|
||||
(fn roundeven(x: f16) -> (f16); => roundevenf16);
|
||||
(fn scalbn(x: f16, n: i32) -> (f16); => scalbnf16);
|
||||
(fn sqrtf(x: f16) -> (f16); => sqrtf16);
|
||||
(fn truncf(x: f16) -> (f16); => truncf16);
|
||||
// verify-sorted-end
|
||||
|
|
@ -220,18 +223,19 @@ libm_helper! {
|
|||
(fn fabs(x: f128) -> (f128); => fabsf128);
|
||||
(fn fdim(x: f128, y: f128) -> (f128); => fdimf128);
|
||||
(fn floor(x: f128) -> (f128); => floorf128);
|
||||
(fn fmaf128(x: f128, y: f128, z: f128) -> (f128); => fmaf128);
|
||||
(fn fma(x: f128, y: f128, z: f128) -> (f128); => fmaf128);
|
||||
(fn fmax(x: f128, y: f128) -> (f128); => fmaxf128);
|
||||
(fn fmaximum_numf128(x: f128, y: f128) -> (f128); => fmaximum_numf128);
|
||||
(fn fmaximumf128(x: f128, y: f128) -> (f128); => fmaximumf128);
|
||||
(fn fmaximum(x: f128, y: f128) -> (f128); => fmaximumf128);
|
||||
(fn fmaximum_num(x: f128, y: f128) -> (f128); => fmaximum_numf128);
|
||||
(fn fmin(x: f128, y: f128) -> (f128); => fminf128);
|
||||
(fn fminimum_numf128(x: f128, y: f128) -> (f128); => fminimum_numf128);
|
||||
(fn fminimumf128(x: f128, y: f128) -> (f128); => fminimumf128);
|
||||
(fn fminimum(x: f128, y: f128) -> (f128); => fminimumf128);
|
||||
(fn fminimum_num(x: f128, y: f128) -> (f128); => fminimum_numf128);
|
||||
(fn fmod(x: f128, y: f128) -> (f128); => fmodf128);
|
||||
(fn ldexpf128(x: f128, n: i32) -> (f128); => ldexpf128);
|
||||
(fn ldexp(x: f128, n: i32) -> (f128); => ldexpf128);
|
||||
(fn rint(x: f128) -> (f128); => rintf128);
|
||||
(fn round(x: f128) -> (f128); => roundf128);
|
||||
(fn scalbnf128(x: f128, n: i32) -> (f128); => ldexpf128);
|
||||
(fn roundeven(x: f128) -> (f128); => roundevenf128);
|
||||
(fn scalbn(x: f128, n: i32) -> (f128); => scalbnf128);
|
||||
(fn sqrt(x: f128) -> (f128); => sqrtf128);
|
||||
(fn trunc(x: f128) -> (f128); => truncf128);
|
||||
// verify-sorted-end
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ pub use fmin::fmin;
|
|||
pub use fminimum::fminimum;
|
||||
pub use fminimum_num::fminimum_num;
|
||||
pub use fmod::fmod;
|
||||
pub use rint::rint;
|
||||
pub use rint::rint_round;
|
||||
pub use round::round;
|
||||
pub use scalbn::scalbn;
|
||||
pub use sqrt::sqrt;
|
||||
|
|
|
|||
|
|
@ -2,27 +2,31 @@
|
|||
/* origin: musl src/math/rint.c */
|
||||
|
||||
use super::super::Float;
|
||||
use super::super::support::{FpResult, Round};
|
||||
|
||||
pub fn rint<F: Float>(x: F) -> F {
|
||||
/// IEEE 754-2019 `roundToIntegralExact`, which respects rounding mode and raises inexact if
|
||||
/// applicable.
|
||||
pub fn rint_round<F: Float>(x: F, _round: Round) -> FpResult<F> {
|
||||
let toint = F::ONE / F::EPSILON;
|
||||
let e = x.exp();
|
||||
let positive = x.is_sign_positive();
|
||||
|
||||
// On i386 `force_eval!` must be used to force rounding via storage to memory. Otherwise,
|
||||
// the excess precission from x87 would cause an incorrect final result.
|
||||
let use_force = cfg!(x86_no_sse) && F::BITS == 32 || F::BITS == 64;
|
||||
let force = |x| {
|
||||
if cfg!(x86_no_sse) && (F::BITS == 32 || F::BITS == 64) { force_eval!(x) } else { x }
|
||||
};
|
||||
|
||||
if e >= F::EXP_BIAS + F::SIG_BITS {
|
||||
let res = if e >= F::EXP_BIAS + F::SIG_BITS {
|
||||
// No fractional part; exact result can be returned.
|
||||
x
|
||||
} else {
|
||||
// Apply a net-zero adjustment that nudges `y` in the direction of the rounding mode.
|
||||
// Apply a net-zero adjustment that nudges `y` in the direction of the rounding mode. For
|
||||
// Rust this is always nearest, but ideally it would take `round` into account.
|
||||
let y = if positive {
|
||||
let tmp = if use_force { force_eval!(x) } else { x } + toint;
|
||||
(if use_force { force_eval!(tmp) } else { tmp } - toint)
|
||||
force(force(x) + toint) - toint
|
||||
} else {
|
||||
let tmp = if use_force { force_eval!(x) } else { x } - toint;
|
||||
(if use_force { force_eval!(tmp) } else { tmp } + toint)
|
||||
force(force(x) - toint) + toint
|
||||
};
|
||||
|
||||
if y == F::ZERO {
|
||||
|
|
@ -31,42 +35,85 @@ pub fn rint<F: Float>(x: F) -> F {
|
|||
} else {
|
||||
y
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
FpResult::ok(res)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::support::{Hexf, Int, Status};
|
||||
|
||||
#[test]
|
||||
fn zeroes_f32() {
|
||||
assert_biteq!(rint(0.0_f32), 0.0_f32);
|
||||
assert_biteq!(rint(-0.0_f32), -0.0_f32);
|
||||
fn spec_test<F: Float>(cases: &[(F, F, Status)]) {
|
||||
let roundtrip = [F::ZERO, F::ONE, F::NEG_ONE, F::NEG_ZERO, F::INFINITY, F::NEG_INFINITY];
|
||||
|
||||
for x in roundtrip {
|
||||
let FpResult { val, status } = rint_round(x, Round::Nearest);
|
||||
assert_biteq!(val, x, "rint_round({})", Hexf(x));
|
||||
assert_eq!(status, Status::OK, "{}", Hexf(x));
|
||||
}
|
||||
|
||||
for &(x, res, res_stat) in cases {
|
||||
let FpResult { val, status } = rint_round(x, Round::Nearest);
|
||||
assert_biteq!(val, res, "rint_round({})", Hexf(x));
|
||||
assert_eq!(status, res_stat, "{}", Hexf(x));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sanity_check_f32() {
|
||||
assert_biteq!(rint(-1.0_f32), -1.0);
|
||||
assert_biteq!(rint(2.8_f32), 3.0);
|
||||
assert_biteq!(rint(-0.5_f32), -0.0);
|
||||
assert_biteq!(rint(0.5_f32), 0.0);
|
||||
assert_biteq!(rint(-1.5_f32), -2.0);
|
||||
assert_biteq!(rint(1.5_f32), 2.0);
|
||||
#[cfg(f16_enabled)]
|
||||
fn spec_tests_f16() {
|
||||
let cases = [];
|
||||
spec_test::<f16>(&cases);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn zeroes_f64() {
|
||||
assert_biteq!(rint(0.0_f64), 0.0_f64);
|
||||
assert_biteq!(rint(-0.0_f64), -0.0_f64);
|
||||
fn spec_tests_f32() {
|
||||
let cases = [
|
||||
(0.1, 0.0, Status::OK),
|
||||
(-0.1, -0.0, Status::OK),
|
||||
(0.5, 0.0, Status::OK),
|
||||
(-0.5, -0.0, Status::OK),
|
||||
(0.9, 1.0, Status::OK),
|
||||
(-0.9, -1.0, Status::OK),
|
||||
(1.1, 1.0, Status::OK),
|
||||
(-1.1, -1.0, Status::OK),
|
||||
(1.5, 2.0, Status::OK),
|
||||
(-1.5, -2.0, Status::OK),
|
||||
(1.9, 2.0, Status::OK),
|
||||
(-1.9, -2.0, Status::OK),
|
||||
(2.8, 3.0, Status::OK),
|
||||
(-2.8, -3.0, Status::OK),
|
||||
];
|
||||
spec_test::<f32>(&cases);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sanity_check_f64() {
|
||||
assert_biteq!(rint(-1.0_f64), -1.0);
|
||||
assert_biteq!(rint(2.8_f64), 3.0);
|
||||
assert_biteq!(rint(-0.5_f64), -0.0);
|
||||
assert_biteq!(rint(0.5_f64), 0.0);
|
||||
assert_biteq!(rint(-1.5_f64), -2.0);
|
||||
assert_biteq!(rint(1.5_f64), 2.0);
|
||||
fn spec_tests_f64() {
|
||||
let cases = [
|
||||
(0.1, 0.0, Status::OK),
|
||||
(-0.1, -0.0, Status::OK),
|
||||
(0.5, 0.0, Status::OK),
|
||||
(-0.5, -0.0, Status::OK),
|
||||
(0.9, 1.0, Status::OK),
|
||||
(-0.9, -1.0, Status::OK),
|
||||
(1.1, 1.0, Status::OK),
|
||||
(-1.1, -1.0, Status::OK),
|
||||
(1.5, 2.0, Status::OK),
|
||||
(-1.5, -2.0, Status::OK),
|
||||
(1.9, 2.0, Status::OK),
|
||||
(-1.9, -2.0, Status::OK),
|
||||
(2.8, 3.0, Status::OK),
|
||||
(-2.8, -3.0, Status::OK),
|
||||
];
|
||||
spec_test::<f64>(&cases);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(f128_enabled)]
|
||||
fn spec_tests_f128() {
|
||||
let cases = [];
|
||||
spec_test::<f128>(&cases);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -207,8 +207,8 @@ mod remainderf;
|
|||
mod remquo;
|
||||
mod remquof;
|
||||
mod rint;
|
||||
mod rintf;
|
||||
mod round;
|
||||
mod roundeven;
|
||||
mod roundf;
|
||||
mod scalbn;
|
||||
mod scalbnf;
|
||||
|
|
@ -313,9 +313,9 @@ pub use self::remainder::remainder;
|
|||
pub use self::remainderf::remainderf;
|
||||
pub use self::remquo::remquo;
|
||||
pub use self::remquof::remquof;
|
||||
pub use self::rint::rint;
|
||||
pub use self::rintf::rintf;
|
||||
pub use self::rint::{rint, rintf};
|
||||
pub use self::round::round;
|
||||
pub use self::roundeven::{roundeven, roundevenf};
|
||||
pub use self::roundf::roundf;
|
||||
pub use self::scalbn::scalbn;
|
||||
pub use self::scalbnf::scalbnf;
|
||||
|
|
@ -346,7 +346,6 @@ cfg_if! {
|
|||
mod floorf16;
|
||||
mod fmodf16;
|
||||
mod ldexpf16;
|
||||
mod rintf16;
|
||||
mod roundf16;
|
||||
mod scalbnf16;
|
||||
mod sqrtf16;
|
||||
|
|
@ -364,7 +363,8 @@ cfg_if! {
|
|||
pub use self::fminimum_fmaximum_num::{fmaximum_numf16, fminimum_numf16};
|
||||
pub use self::fmodf16::fmodf16;
|
||||
pub use self::ldexpf16::ldexpf16;
|
||||
pub use self::rintf16::rintf16;
|
||||
pub use self::rint::rintf16;
|
||||
pub use self::roundeven::roundevenf16;
|
||||
pub use self::roundf16::roundf16;
|
||||
pub use self::scalbnf16::scalbnf16;
|
||||
pub use self::sqrtf16::sqrtf16;
|
||||
|
|
@ -384,7 +384,6 @@ cfg_if! {
|
|||
mod fmaf128;
|
||||
mod fmodf128;
|
||||
mod ldexpf128;
|
||||
mod rintf128;
|
||||
mod roundf128;
|
||||
mod scalbnf128;
|
||||
mod sqrtf128;
|
||||
|
|
@ -403,7 +402,8 @@ cfg_if! {
|
|||
pub use self::fminimum_fmaximum_num::{fmaximum_numf128, fminimum_numf128};
|
||||
pub use self::fmodf128::fmodf128;
|
||||
pub use self::ldexpf128::ldexpf128;
|
||||
pub use self::rintf128::rintf128;
|
||||
pub use self::rint::rintf128;
|
||||
pub use self::roundeven::roundevenf128;
|
||||
pub use self::roundf128::roundf128;
|
||||
pub use self::scalbnf128::scalbnf128;
|
||||
pub use self::sqrtf128::sqrtf128;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,27 @@
|
|||
use super::support::Round;
|
||||
|
||||
/// Round `x` to the nearest integer, breaking ties toward even.
|
||||
#[cfg(f16_enabled)]
|
||||
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
|
||||
pub fn rintf16(x: f16) -> f16 {
|
||||
super::generic::rint_round(x, Round::Nearest).val
|
||||
}
|
||||
|
||||
/// Round `x` to the nearest integer, breaking ties toward even.
|
||||
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
|
||||
pub fn rintf(x: f32) -> f32 {
|
||||
select_implementation! {
|
||||
name: rintf,
|
||||
use_arch: any(
|
||||
all(target_arch = "wasm32", intrinsics_enabled),
|
||||
all(target_arch = "aarch64", target_feature = "neon", target_endian = "little"),
|
||||
),
|
||||
args: x,
|
||||
}
|
||||
|
||||
super::generic::rint_round(x, Round::Nearest).val
|
||||
}
|
||||
|
||||
/// Round `x` to the nearest integer, breaking ties toward even.
|
||||
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
|
||||
pub fn rint(x: f64) -> f64 {
|
||||
|
|
@ -10,5 +34,12 @@ pub fn rint(x: f64) -> f64 {
|
|||
args: x,
|
||||
}
|
||||
|
||||
super::generic::rint(x)
|
||||
super::generic::rint_round(x, Round::Nearest).val
|
||||
}
|
||||
|
||||
/// Round `x` to the nearest integer, breaking ties toward even.
|
||||
#[cfg(f128_enabled)]
|
||||
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
|
||||
pub fn rintf128(x: f128) -> f128 {
|
||||
super::generic::rint_round(x, Round::Nearest).val
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,14 +0,0 @@
|
|||
/// Round `x` to the nearest integer, breaking ties toward even.
|
||||
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
|
||||
pub fn rintf(x: f32) -> f32 {
|
||||
select_implementation! {
|
||||
name: rintf,
|
||||
use_arch: any(
|
||||
all(target_arch = "wasm32", intrinsics_enabled),
|
||||
all(target_arch = "aarch64", target_feature = "neon", target_endian = "little"),
|
||||
),
|
||||
args: x,
|
||||
}
|
||||
|
||||
super::generic::rint(x)
|
||||
}
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
/// Round `x` to the nearest integer, breaking ties toward even.
|
||||
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
|
||||
pub fn rintf128(x: f128) -> f128 {
|
||||
super::generic::rint(x)
|
||||
}
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
/// Round `x` to the nearest integer, breaking ties toward even.
|
||||
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
|
||||
pub fn rintf16(x: f16) -> f16 {
|
||||
super::generic::rint(x)
|
||||
}
|
||||
35
library/compiler-builtins/libm/src/math/roundeven.rs
Normal file
35
library/compiler-builtins/libm/src/math/roundeven.rs
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
use super::support::{Float, Round};
|
||||
|
||||
/// Round `x` to the nearest integer, breaking ties toward even. This is IEEE 754
|
||||
/// `roundToIntegralTiesToEven`.
|
||||
#[cfg(f16_enabled)]
|
||||
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
|
||||
pub fn roundevenf16(x: f16) -> f16 {
|
||||
roundeven_impl(x)
|
||||
}
|
||||
|
||||
/// Round `x` to the nearest integer, breaking ties toward even. This is IEEE 754
|
||||
/// `roundToIntegralTiesToEven`.
|
||||
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
|
||||
pub fn roundevenf(x: f32) -> f32 {
|
||||
roundeven_impl(x)
|
||||
}
|
||||
|
||||
/// Round `x` to the nearest integer, breaking ties toward even. This is IEEE 754
|
||||
/// `roundToIntegralTiesToEven`.
|
||||
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
|
||||
pub fn roundeven(x: f64) -> f64 {
|
||||
roundeven_impl(x)
|
||||
}
|
||||
|
||||
/// Round `x` to the nearest integer, breaking ties toward even. This is IEEE 754
|
||||
/// `roundToIntegralTiesToEven`.
|
||||
#[cfg(f128_enabled)]
|
||||
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
|
||||
pub fn roundevenf128(x: f128) -> f128 {
|
||||
roundeven_impl(x)
|
||||
}
|
||||
|
||||
pub fn roundeven_impl<F: Float>(x: F) -> F {
|
||||
super::generic::rint_round(x, Round::Nearest).val
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue