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:
Trevor Gross 2025-02-11 00:17:32 +00:00 committed by Trevor Gross
parent 2a3ef8b9a2
commit 53a055049c
20 changed files with 364 additions and 102 deletions

View file

@ -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`

View file

@ -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,

View file

@ -154,6 +154,10 @@ libm_macros::for_each_function! {
| ldexpf16
| rintf128
| rintf16
| roundeven
| roundevenf
| roundevenf128
| roundevenf16
| roundf128
| roundf16
| scalbnf128

View file

@ -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[..],

View file

@ -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![]
}

View file

@ -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;
}

View file

@ -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
{

View file

@ -126,6 +126,10 @@ libm_macros::for_each_function! {
ldexpf16,
rintf128,
rintf16,
roundeven,
roundevenf,
roundevenf128,
roundevenf16,
roundf128,
roundf16,
scalbnf128,

View file

@ -123,6 +123,10 @@ fn do_eval(basis: &str, op: &str, inputs: &[&str]) {
| ldexpf16
| rintf128
| rintf16
| roundeven
| roundevenf
| roundevenf128
| roundevenf16
| roundf128
| roundf16
| scalbnf128

View file

@ -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",

View file

@ -125,6 +125,10 @@ rintf
rintf128
rintf16
round
roundeven
roundevenf
roundevenf128
roundevenf16
roundf
roundf128
roundf16

View file

@ -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

View file

@ -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;

View file

@ -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);
}
}

View file

@ -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;

View file

@ -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
}

View file

@ -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)
}

View file

@ -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)
}

View file

@ -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)
}

View 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
}