Skip to content

Commit 753d69f

Browse files
authored
Merge pull request rust-lang#454 from tgross35/generic-rint
Add `rintf16` and `rintf128`
2 parents 5e9ded4 + d2da7f7 commit 753d69f

File tree

16 files changed

+130
-100
lines changed

16 files changed

+130
-100
lines changed

crates/compiler-builtins-smoke-test/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,8 @@ no_mangle! {
145145
remquof(x: f32, y: f32 | q: &mut c_int) -> f32;
146146
rint(x: f64) -> f64;
147147
rintf(x: f32) -> f32;
148+
rintf128(x: f128) -> f128;
149+
rintf16(x: f16) -> f16;
148150
round(x: f64) -> f64;
149151
roundf(x: f32) -> f32;
150152
scalbn(x: f64, y: c_int) -> f64;

crates/libm-macros/src/shared.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option<Signature>, &[&str])]
99
FloatTy::F16,
1010
Signature { args: &[Ty::F16], returns: &[Ty::F16] },
1111
None,
12-
&["ceilf16", "fabsf16", "floorf16", "sqrtf16", "truncf16"],
12+
&["ceilf16", "fabsf16", "floorf16", "rintf16", "sqrtf16", "truncf16"],
1313
),
1414
(
1515
// `fn(f32) -> f32`
@@ -40,7 +40,7 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option<Signature>, &[&str])]
4040
FloatTy::F128,
4141
Signature { args: &[Ty::F128], returns: &[Ty::F128] },
4242
None,
43-
&["ceilf128", "fabsf128", "floorf128", "sqrtf128", "truncf128"],
43+
&["ceilf128", "fabsf128", "floorf128", "rintf128", "sqrtf128", "truncf128"],
4444
),
4545
(
4646
// `(f16, f16) -> f16`

crates/libm-test/benches/icount.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,8 @@ main!(
149149
icount_bench_remquo_group,
150150
icount_bench_remquof_group,
151151
icount_bench_rint_group,
152+
icount_bench_rintf128_group,
153+
icount_bench_rintf16_group,
152154
icount_bench_rintf_group,
153155
icount_bench_round_group,
154156
icount_bench_roundf_group,

crates/libm-test/benches/random.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,8 @@ libm_macros::for_each_function! {
127127
| fdimf16
128128
| floorf128
129129
| floorf16
130+
| rintf128
131+
| rintf16
130132
| sqrtf128
131133
| sqrtf16
132134
| truncf128

crates/libm-test/src/mpfloat.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,8 @@ libm_macros::for_each_function! {
170170
remquof,
171171
rint,
172172
rintf,
173+
rintf128,
174+
rintf16,
173175
round,
174176
roundf,
175177
scalbn,
@@ -240,17 +242,19 @@ impl_no_round! {
240242

241243
#[cfg(f16_enabled)]
242244
impl_no_round! {
243-
fabsf16 => abs_mut;
244245
ceilf16 => ceil_mut;
246+
fabsf16 => abs_mut;
245247
floorf16 => floor_mut;
248+
rintf16 => round_even_mut; // FIXME: respect rounding mode
246249
truncf16 => trunc_mut;
247250
}
248251

249252
#[cfg(f128_enabled)]
250253
impl_no_round! {
251-
fabsf128 => abs_mut;
252254
ceilf128 => ceil_mut;
255+
fabsf128 => abs_mut;
253256
floorf128 => floor_mut;
257+
rintf128 => round_even_mut; // FIXME: respect rounding mode
254258
truncf128 => trunc_mut;
255259
}
256260

crates/libm-test/tests/compare_built_musl.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,9 +89,11 @@ libm_macros::for_each_function! {
8989
fdimf16,
9090
floorf128,
9191
floorf16,
92+
rintf128,
93+
rintf16,
94+
sqrtf128,
95+
sqrtf16,
9296
truncf128,
9397
truncf16,
94-
sqrtf16,
95-
sqrtf128,
9698
],
9799
}

crates/util/src/main.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,8 @@ fn do_eval(basis: &str, op: &str, inputs: &[&str]) {
9494
| fdimf16
9595
| floorf128
9696
| floorf16
97+
| rintf128
98+
| rintf16
9799
| sqrtf128
98100
| sqrtf16
99101
| truncf128

etc/function-definitions.json

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -654,6 +654,7 @@
654654
"src/libm_helper.rs",
655655
"src/math/arch/aarch64.rs",
656656
"src/math/arch/wasm32.rs",
657+
"src/math/generic/rint.rs",
657658
"src/math/rint.rs"
658659
],
659660
"type": "f64"
@@ -662,10 +663,25 @@
662663
"sources": [
663664
"src/math/arch/aarch64.rs",
664665
"src/math/arch/wasm32.rs",
666+
"src/math/generic/rint.rs",
665667
"src/math/rintf.rs"
666668
],
667669
"type": "f32"
668670
},
671+
"rintf128": {
672+
"sources": [
673+
"src/math/generic/rint.rs",
674+
"src/math/rintf128.rs"
675+
],
676+
"type": "f128"
677+
},
678+
"rintf16": {
679+
"sources": [
680+
"src/math/generic/rint.rs",
681+
"src/math/rintf16.rs"
682+
],
683+
"type": "f16"
684+
},
669685
"round": {
670686
"sources": [
671687
"src/libm_helper.rs",

etc/function-list.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,8 @@ remquo
9797
remquof
9898
rint
9999
rintf
100+
rintf128
101+
rintf16
100102
round
101103
roundf
102104
scalbn

src/math/generic/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ mod copysign;
33
mod fabs;
44
mod fdim;
55
mod floor;
6+
mod rint;
67
mod sqrt;
78
mod trunc;
89

@@ -11,5 +12,6 @@ pub use copysign::copysign;
1112
pub use fabs::fabs;
1213
pub use fdim::fdim;
1314
pub use floor::floor;
15+
pub use rint::rint;
1416
pub use sqrt::sqrt;
1517
pub use trunc::trunc;

src/math/generic/rint.rs

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/* SPDX-License-Identifier: MIT */
2+
/* origin: musl src/math/rint.c */
3+
4+
use super::super::Float;
5+
6+
pub fn rint<F: Float>(x: F) -> F {
7+
let toint = F::ONE / F::EPSILON;
8+
let e = x.exp();
9+
let positive = x.is_sign_positive();
10+
11+
// On i386 `force_eval!` must be used to force rounding via storage to memory. Otherwise,
12+
// the excess precission from x87 would cause an incorrect final result.
13+
let use_force = cfg!(x86_no_sse) && F::BITS == 32 || F::BITS == 64;
14+
15+
if e >= F::EXP_BIAS + F::SIG_BITS {
16+
// No fractional part; exact result can be returned.
17+
x
18+
} else {
19+
// Apply a net-zero adjustment that nudges `y` in the direction of the rounding mode.
20+
let y = if positive {
21+
let tmp = if use_force { force_eval!(x) } else { x } + toint;
22+
(if use_force { force_eval!(tmp) } else { tmp } - toint)
23+
} else {
24+
let tmp = if use_force { force_eval!(x) } else { x } - toint;
25+
(if use_force { force_eval!(tmp) } else { tmp } + toint)
26+
};
27+
28+
if y == F::ZERO {
29+
// A zero result takes the sign of the input.
30+
if positive { F::ZERO } else { F::NEG_ZERO }
31+
} else {
32+
y
33+
}
34+
}
35+
}
36+
37+
#[cfg(test)]
38+
mod tests {
39+
use super::*;
40+
41+
#[test]
42+
fn zeroes_f32() {
43+
assert_biteq!(rint(0.0_f32), 0.0_f32);
44+
assert_biteq!(rint(-0.0_f32), -0.0_f32);
45+
}
46+
47+
#[test]
48+
fn sanity_check_f32() {
49+
assert_biteq!(rint(-1.0_f32), -1.0);
50+
assert_biteq!(rint(2.8_f32), 3.0);
51+
assert_biteq!(rint(-0.5_f32), -0.0);
52+
assert_biteq!(rint(0.5_f32), 0.0);
53+
assert_biteq!(rint(-1.5_f32), -2.0);
54+
assert_biteq!(rint(1.5_f32), 2.0);
55+
}
56+
57+
#[test]
58+
fn zeroes_f64() {
59+
assert_biteq!(rint(0.0_f64), 0.0_f64);
60+
assert_biteq!(rint(-0.0_f64), -0.0_f64);
61+
}
62+
63+
#[test]
64+
fn sanity_check_f64() {
65+
assert_biteq!(rint(-1.0_f64), -1.0);
66+
assert_biteq!(rint(2.8_f64), 3.0);
67+
assert_biteq!(rint(-0.5_f64), -0.0);
68+
assert_biteq!(rint(0.5_f64), 0.0);
69+
assert_biteq!(rint(-1.5_f64), -2.0);
70+
assert_biteq!(rint(1.5_f64), 2.0);
71+
}
72+
}

src/math/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,7 @@ cfg_if! {
346346
mod fabsf16;
347347
mod fdimf16;
348348
mod floorf16;
349+
mod rintf16;
349350
mod sqrtf16;
350351
mod truncf16;
351352

@@ -354,6 +355,7 @@ cfg_if! {
354355
pub use self::fabsf16::fabsf16;
355356
pub use self::fdimf16::fdimf16;
356357
pub use self::floorf16::floorf16;
358+
pub use self::rintf16::rintf16;
357359
pub use self::sqrtf16::sqrtf16;
358360
pub use self::truncf16::truncf16;
359361
}
@@ -366,6 +368,7 @@ cfg_if! {
366368
mod fabsf128;
367369
mod fdimf128;
368370
mod floorf128;
371+
mod rintf128;
369372
mod sqrtf128;
370373
mod truncf128;
371374

@@ -374,6 +377,7 @@ cfg_if! {
374377
pub use self::fabsf128::fabsf128;
375378
pub use self::fdimf128::fdimf128;
376379
pub use self::floorf128::floorf128;
380+
pub use self::rintf128::rintf128;
377381
pub use self::sqrtf128::sqrtf128;
378382
pub use self::truncf128::truncf128;
379383
}

src/math/rint.rs

Lines changed: 2 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
/// Round `x` to the nearest integer, breaking ties toward even.
12
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
23
pub fn rint(x: f64) -> f64 {
34
select_implementation! {
@@ -9,51 +10,5 @@ pub fn rint(x: f64) -> f64 {
910
args: x,
1011
}
1112

12-
let one_over_e = 1.0 / f64::EPSILON;
13-
let as_u64: u64 = x.to_bits();
14-
let exponent: u64 = (as_u64 >> 52) & 0x7ff;
15-
let is_positive = (as_u64 >> 63) == 0;
16-
if exponent >= 0x3ff + 52 {
17-
x
18-
} else {
19-
let ans = if is_positive {
20-
#[cfg(all(target_arch = "x86", not(target_feature = "sse2")))]
21-
let x = force_eval!(x);
22-
let xplusoneovere = x + one_over_e;
23-
#[cfg(all(target_arch = "x86", not(target_feature = "sse2")))]
24-
let xplusoneovere = force_eval!(xplusoneovere);
25-
xplusoneovere - one_over_e
26-
} else {
27-
#[cfg(all(target_arch = "x86", not(target_feature = "sse2")))]
28-
let x = force_eval!(x);
29-
let xminusoneovere = x - one_over_e;
30-
#[cfg(all(target_arch = "x86", not(target_feature = "sse2")))]
31-
let xminusoneovere = force_eval!(xminusoneovere);
32-
xminusoneovere + one_over_e
33-
};
34-
35-
if ans == 0.0 { if is_positive { 0.0 } else { -0.0 } } else { ans }
36-
}
37-
}
38-
39-
// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520
40-
#[cfg(not(target_arch = "powerpc64"))]
41-
#[cfg(test)]
42-
mod tests {
43-
use super::rint;
44-
45-
#[test]
46-
fn negative_zero() {
47-
assert_eq!(rint(-0.0_f64).to_bits(), (-0.0_f64).to_bits());
48-
}
49-
50-
#[test]
51-
fn sanity_check() {
52-
assert_eq!(rint(-1.0), -1.0);
53-
assert_eq!(rint(2.8), 3.0);
54-
assert_eq!(rint(-0.5), -0.0);
55-
assert_eq!(rint(0.5), 0.0);
56-
assert_eq!(rint(-1.5), -2.0);
57-
assert_eq!(rint(1.5), 2.0);
58-
}
13+
super::generic::rint(x)
5914
}

src/math/rintf.rs

Lines changed: 2 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
/// Round `x` to the nearest integer, breaking ties toward even.
12
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
23
pub fn rintf(x: f32) -> f32 {
34
select_implementation! {
@@ -9,51 +10,5 @@ pub fn rintf(x: f32) -> f32 {
910
args: x,
1011
}
1112

12-
let one_over_e = 1.0 / f32::EPSILON;
13-
let as_u32: u32 = x.to_bits();
14-
let exponent: u32 = (as_u32 >> 23) & 0xff;
15-
let is_positive = (as_u32 >> 31) == 0;
16-
if exponent >= 0x7f + 23 {
17-
x
18-
} else {
19-
let ans = if is_positive {
20-
#[cfg(all(target_arch = "x86", not(target_feature = "sse2")))]
21-
let x = force_eval!(x);
22-
let xplusoneovere = x + one_over_e;
23-
#[cfg(all(target_arch = "x86", not(target_feature = "sse2")))]
24-
let xplusoneovere = force_eval!(xplusoneovere);
25-
xplusoneovere - one_over_e
26-
} else {
27-
#[cfg(all(target_arch = "x86", not(target_feature = "sse2")))]
28-
let x = force_eval!(x);
29-
let xminusoneovere = x - one_over_e;
30-
#[cfg(all(target_arch = "x86", not(target_feature = "sse2")))]
31-
let xminusoneovere = force_eval!(xminusoneovere);
32-
xminusoneovere + one_over_e
33-
};
34-
35-
if ans == 0.0 { if is_positive { 0.0 } else { -0.0 } } else { ans }
36-
}
37-
}
38-
39-
// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520
40-
#[cfg(not(target_arch = "powerpc64"))]
41-
#[cfg(test)]
42-
mod tests {
43-
use super::rintf;
44-
45-
#[test]
46-
fn negative_zero() {
47-
assert_eq!(rintf(-0.0_f32).to_bits(), (-0.0_f32).to_bits());
48-
}
49-
50-
#[test]
51-
fn sanity_check() {
52-
assert_eq!(rintf(-1.0), -1.0);
53-
assert_eq!(rintf(2.8), 3.0);
54-
assert_eq!(rintf(-0.5), -0.0);
55-
assert_eq!(rintf(0.5), 0.0);
56-
assert_eq!(rintf(-1.5), -2.0);
57-
assert_eq!(rintf(1.5), 2.0);
58-
}
13+
super::generic::rint(x)
5914
}

src/math/rintf128.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
/// Round `x` to the nearest integer, breaking ties toward even.
2+
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
3+
pub fn rintf128(x: f128) -> f128 {
4+
super::generic::rint(x)
5+
}

src/math/rintf16.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
/// Round `x` to the nearest integer, breaking ties toward even.
2+
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
3+
pub fn rintf16(x: f16) -> f16 {
4+
super::generic::rint(x)
5+
}

0 commit comments

Comments
 (0)