Skip to content
This repository was archived by the owner on Apr 28, 2025. It is now read-only.

Commit 010201f

Browse files
authored
Merge pull request #510 from tgross35/replace-fenv
Migrate away from nonfunctional `fenv` stubs
2 parents 70db186 + b815982 commit 010201f

File tree

12 files changed

+470
-178
lines changed

12 files changed

+470
-178
lines changed

libm/crates/libm-test/src/f8_impl.rs

+1
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ impl Float for f8 {
3232
const INFINITY: Self = Self(0b0_1111_000);
3333
const NEG_INFINITY: Self = Self(0b1_1111_000);
3434
const NAN: Self = Self(0b0_1111_100);
35+
const MIN_POSITIVE_NORMAL: Self = Self(1 << Self::SIG_BITS);
3536
// FIXME: incorrect values
3637
const EPSILON: Self = Self::ZERO;
3738
const PI: Self = Self::ZERO;

libm/src/math/cbrt.rs

+13-12
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,15 @@
55
*/
66

77
use super::Float;
8-
use super::fenv::Rounding;
9-
use super::support::cold_path;
8+
use super::support::{FpResult, Round, cold_path};
109

1110
/// Compute the cube root of the argument.
1211
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
1312
pub fn cbrt(x: f64) -> f64 {
13+
cbrt_round(x, Round::Nearest).val
14+
}
15+
16+
pub fn cbrt_round(x: f64, round: Round) -> FpResult<f64> {
1417
const ESCALE: [f64; 3] = [
1518
1.0,
1619
hf64!("0x1.428a2f98d728bp+0"), /* 2^(1/3) */
@@ -33,8 +36,6 @@ pub fn cbrt(x: f64) -> f64 {
3336

3437
let off = [hf64!("0x1p-53"), 0.0, 0.0, 0.0];
3538

36-
let rm = Rounding::get();
37-
3839
/* rm=0 for rounding to nearest, and other values for directed roundings */
3940
let hx: u64 = x.to_bits();
4041
let mut mant: u64 = hx & f64::SIG_MASK;
@@ -51,7 +52,7 @@ pub fn cbrt(x: f64) -> f64 {
5152
to that for x a signaling NaN, it correctly triggers
5253
the invalid exception. */
5354
if e == f64::EXP_SAT || ix == 0 {
54-
return x + x;
55+
return FpResult::ok(x + x);
5556
}
5657

5758
let nz = ix.leading_zeros() - 11; /* subnormal */
@@ -124,8 +125,8 @@ pub fn cbrt(x: f64) -> f64 {
124125
* from ulp(1);
125126
* for rounding to nearest, ady0 is tiny when dy is near from 1/2 ulp(1),
126127
* or from 3/2 ulp(1). */
127-
let mut ady0: f64 = (ady - off[rm as usize]).abs();
128-
let mut ady1: f64 = (ady - (hf64!("0x1p-52") + off[rm as usize])).abs();
128+
let mut ady0: f64 = (ady - off[round as usize]).abs();
129+
let mut ady1: f64 = (ady - (hf64!("0x1p-52") + off[round as usize])).abs();
129130

130131
if ady0 < hf64!("0x1p-75") || ady1 < hf64!("0x1p-75") {
131132
cold_path();
@@ -140,8 +141,8 @@ pub fn cbrt(x: f64) -> f64 {
140141
dy = (y1 - y) - dy;
141142
y1 = y;
142143
ady = dy.abs();
143-
ady0 = (ady - off[rm as usize]).abs();
144-
ady1 = (ady - (hf64!("0x1p-52") + off[rm as usize])).abs();
144+
ady0 = (ady - off[round as usize]).abs();
145+
ady1 = (ady - (hf64!("0x1p-52") + off[round as usize])).abs();
145146

146147
if ady0 < hf64!("0x1p-98") || ady1 < hf64!("0x1p-98") {
147148
cold_path();
@@ -157,7 +158,7 @@ pub fn cbrt(x: f64) -> f64 {
157158
y1 = hf64!("0x1.de87aa837820fp+0").copysign(zz);
158159
}
159160

160-
if rm != Rounding::Nearest {
161+
if round != Round::Nearest {
161162
let wlist = [
162163
(hf64!("0x1.3a9ccd7f022dbp+0"), hf64!("0x1.1236160ba9b93p+0")), // ~ 0x1.1236160ba9b930000000000001e7e8fap+0
163164
(hf64!("0x1.7845d2faac6fep+0"), hf64!("0x1.23115e657e49cp+0")), // ~ 0x1.23115e657e49c0000000000001d7a799p+0
@@ -170,7 +171,7 @@ pub fn cbrt(x: f64) -> f64 {
170171

171172
for (a, b) in wlist {
172173
if azz == a {
173-
let tmp = if rm as u64 + sign == 2 { hf64!("0x1p-52") } else { 0.0 };
174+
let tmp = if round as u64 + sign == 2 { hf64!("0x1p-52") } else { 0.0 };
174175
y1 = (b + tmp).copysign(zz);
175176
}
176177
}
@@ -194,7 +195,7 @@ pub fn cbrt(x: f64) -> f64 {
194195
}
195196
}
196197

197-
f64::from_bits(cvt3)
198+
FpResult::ok(f64::from_bits(cvt3))
198199
}
199200

200201
fn fmaf64(x: f64, y: f64, z: f64) -> f64 {

libm/src/math/fenv.rs

-49
This file was deleted.

libm/src/math/generic/ceil.rs

+76-15
Original file line numberDiff line numberDiff line change
@@ -7,30 +7,35 @@
77
//! performance seems to be better (based on icount) and it does not seem to experience rounding
88
//! errors on i386.
99
10+
use super::super::support::{FpResult, Status};
1011
use super::super::{Float, Int, IntTy, MinInt};
1112

1213
pub fn ceil<F: Float>(x: F) -> F {
14+
ceil_status(x).val
15+
}
16+
17+
pub fn ceil_status<F: Float>(x: F) -> FpResult<F> {
1318
let zero = IntTy::<F>::ZERO;
1419

1520
let mut ix = x.to_bits();
1621
let e = x.exp_unbiased();
1722

1823
// If the represented value has no fractional part, no truncation is needed.
1924
if e >= F::SIG_BITS as i32 {
20-
return x;
25+
return FpResult::ok(x);
2126
}
2227

23-
if e >= 0 {
28+
let status;
29+
let res = if e >= 0 {
2430
// |x| >= 1.0
25-
2631
let m = F::SIG_MASK >> e.unsigned();
2732
if (ix & m) == zero {
2833
// Portion to be masked is already zero; no adjustment needed.
29-
return x;
34+
return FpResult::ok(x);
3035
}
3136

3237
// Otherwise, raise an inexact exception.
33-
force_eval!(x + F::MAX);
38+
status = Status::INEXACT;
3439

3540
if x.is_sign_positive() {
3641
ix += m;
@@ -40,7 +45,11 @@ pub fn ceil<F: Float>(x: F) -> F {
4045
F::from_bits(ix)
4146
} else {
4247
// |x| < 1.0, raise an inexact exception since truncation will happen (unless x == 0).
43-
force_eval!(x + F::MAX);
48+
if ix & F::SIG_MASK == F::Int::ZERO {
49+
status = Status::OK;
50+
} else {
51+
status = Status::INEXACT;
52+
}
4453

4554
if x.is_sign_negative() {
4655
// -1.0 < x <= -0.0; rounding up goes toward -0.0.
@@ -52,18 +61,30 @@ pub fn ceil<F: Float>(x: F) -> F {
5261
// +0.0 remains unchanged
5362
x
5463
}
55-
}
64+
};
65+
66+
FpResult::new(res, status)
5667
}
5768

5869
#[cfg(test)]
5970
mod tests {
6071
use super::*;
72+
use crate::support::Hexf;
6173

6274
/// Test against https://en.cppreference.com/w/cpp/numeric/math/ceil
63-
fn spec_test<F: Float>() {
64-
// Not Asserted: that the current rounding mode has no effect.
65-
for f in [F::ZERO, F::NEG_ZERO, F::INFINITY, F::NEG_INFINITY].iter().copied() {
66-
assert_biteq!(ceil(f), f);
75+
fn spec_test<F: Float>(cases: &[(F, F, Status)]) {
76+
let roundtrip = [F::ZERO, F::ONE, F::NEG_ONE, F::NEG_ZERO, F::INFINITY, F::NEG_INFINITY];
77+
78+
for x in roundtrip {
79+
let FpResult { val, status } = ceil_status(x);
80+
assert_biteq!(val, x, "{}", Hexf(x));
81+
assert_eq!(status, Status::OK, "{}", Hexf(x));
82+
}
83+
84+
for &(x, res, res_stat) in cases {
85+
let FpResult { val, status } = ceil_status(x);
86+
assert_biteq!(val, res, "{}", Hexf(x));
87+
assert_eq!(status, res_stat, "{}", Hexf(x));
6788
}
6889
}
6990

@@ -72,7 +93,17 @@ mod tests {
7293
#[test]
7394
#[cfg(f16_enabled)]
7495
fn spec_tests_f16() {
75-
spec_test::<f16>();
96+
let cases = [
97+
(0.1, 1.0, Status::INEXACT),
98+
(-0.1, -0.0, Status::INEXACT),
99+
(0.9, 1.0, Status::INEXACT),
100+
(-0.9, -0.0, Status::INEXACT),
101+
(1.1, 2.0, Status::INEXACT),
102+
(-1.1, -1.0, Status::INEXACT),
103+
(1.9, 2.0, Status::INEXACT),
104+
(-1.9, -1.0, Status::INEXACT),
105+
];
106+
spec_test::<f16>(&cases);
76107
}
77108

78109
#[test]
@@ -83,7 +114,17 @@ mod tests {
83114

84115
#[test]
85116
fn spec_tests_f32() {
86-
spec_test::<f32>();
117+
let cases = [
118+
(0.1, 1.0, Status::INEXACT),
119+
(-0.1, -0.0, Status::INEXACT),
120+
(0.9, 1.0, Status::INEXACT),
121+
(-0.9, -0.0, Status::INEXACT),
122+
(1.1, 2.0, Status::INEXACT),
123+
(-1.1, -1.0, Status::INEXACT),
124+
(1.9, 2.0, Status::INEXACT),
125+
(-1.9, -1.0, Status::INEXACT),
126+
];
127+
spec_test::<f32>(&cases);
87128
}
88129

89130
#[test]
@@ -94,12 +135,32 @@ mod tests {
94135

95136
#[test]
96137
fn spec_tests_f64() {
97-
spec_test::<f64>();
138+
let cases = [
139+
(0.1, 1.0, Status::INEXACT),
140+
(-0.1, -0.0, Status::INEXACT),
141+
(0.9, 1.0, Status::INEXACT),
142+
(-0.9, -0.0, Status::INEXACT),
143+
(1.1, 2.0, Status::INEXACT),
144+
(-1.1, -1.0, Status::INEXACT),
145+
(1.9, 2.0, Status::INEXACT),
146+
(-1.9, -1.0, Status::INEXACT),
147+
];
148+
spec_test::<f64>(&cases);
98149
}
99150

100151
#[test]
101152
#[cfg(f128_enabled)]
102153
fn spec_tests_f128() {
103-
spec_test::<f128>();
154+
let cases = [
155+
(0.1, 1.0, Status::INEXACT),
156+
(-0.1, -0.0, Status::INEXACT),
157+
(0.9, 1.0, Status::INEXACT),
158+
(-0.9, -0.0, Status::INEXACT),
159+
(1.1, 2.0, Status::INEXACT),
160+
(-1.1, -1.0, Status::INEXACT),
161+
(1.9, 2.0, Status::INEXACT),
162+
(-1.9, -1.0, Status::INEXACT),
163+
];
164+
spec_test::<f128>(&cases);
104165
}
105166
}

0 commit comments

Comments
 (0)