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

Commit 1b89400

Browse files
committed
Change to exhaustive matching for default_ulp
Make it more obvious what the expected ULP for a given routine is. This also narrows ULP to 0 for operations that require exact results.
1 parent 6f6bd11 commit 1b89400

File tree

1 file changed

+91
-39
lines changed

1 file changed

+91
-39
lines changed

crates/libm-test/src/precision.rs

Lines changed: 91 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -4,57 +4,109 @@
44
use core::f32;
55

66
use CheckBasis::{Mpfr, Musl};
7-
use Identifier as Id;
7+
use {BaseName as Bn, Identifier as Id};
88

99
use crate::{BaseName, CheckBasis, CheckCtx, Float, Identifier, Int, TestResult};
1010

1111
/// Type implementing [`IgnoreCase`].
1212
pub struct SpecialCase;
1313

14-
/// Default ULP allowed to differ from musl (note that musl itself may not be accurate).
15-
const MUSL_DEFAULT_ULP: u32 = 2;
16-
17-
/// Default ULP allowed to differ from multiprecision (i.e. infinite) results.
18-
const MP_DEFAULT_ULP: u32 = 1;
19-
2014
/// ULP allowed to differ from the results returned by a test basis.
2115
///
2216
/// Note that these results were obtained using 400M rounds of random inputs, which
2317
/// is not a value used by default.
2418
pub fn default_ulp(ctx: &CheckCtx) -> u32 {
25-
match (&ctx.basis, ctx.fn_ident) {
26-
// Overrides that apply to either basis
27-
// FMA is expected to be infinite precision.
28-
(_, Id::Fma | Id::Fmaf) => 0,
29-
(_, Id::J0 | Id::J0f | Id::J1 | Id::J1f | Id::Y0 | Id::Y0f | Id::Y1 | Id::Y1f) => 800_000,
30-
(_, Id::Jn | Id::Jnf | Id::Yn | Id::Ynf) => 1000,
31-
(_, Id::Erfc | Id::Erfcf) => 4,
32-
33-
// Overrides for musl
34-
#[cfg(x86_no_sse)]
35-
(Musl, Id::Asinh | Id::Asinhf) => 6,
36-
#[cfg(not(target_pointer_width = "64"))]
37-
(Musl, Id::Exp10 | Id::Exp10f) => 4,
38-
(Musl, Id::Lgamma | Id::LgammaR | Id::Lgammaf | Id::LgammafR) => 400,
39-
(Musl, Id::Sincosf) => 500,
40-
(Musl, Id::Tanh | Id::Tanhf) => 4,
41-
(Musl, Id::Tgamma) => 20,
42-
43-
// Overrides for MPFR
44-
(Mpfr, Id::Acosh) => 4,
45-
(Mpfr, Id::Acoshf) => 4,
46-
(Mpfr, Id::Asinh | Id::Asinhf) => 2,
47-
(Mpfr, Id::Atanh | Id::Atanhf) => 2,
48-
(Mpfr, Id::Exp10 | Id::Exp10f) => 6,
49-
(Mpfr, Id::Lgamma | Id::LgammaR | Id::Lgammaf | Id::LgammafR) => 16,
50-
(Mpfr, Id::Sinh | Id::Sinhf) => 2,
51-
(Mpfr, Id::Tanh | Id::Tanhf) => 2,
52-
(Mpfr, Id::Tgamma) => 20,
53-
54-
// Defaults
55-
(Musl, _) => MUSL_DEFAULT_ULP,
56-
(Mpfr, _) => MP_DEFAULT_ULP,
19+
// ULP compared to the infinite (MPFR) result.
20+
let mut ulp = match ctx.base_name {
21+
// Operations that require exact results. This list should correlate with what we
22+
// have documented at <https://doc.rust-lang.org/std/primitive.f32.html>.
23+
Bn::Ceil
24+
| Bn::Copysign
25+
| Bn::Fabs
26+
| Bn::Fdim
27+
| Bn::Floor
28+
| Bn::Fma
29+
| Bn::Fmax
30+
| Bn::Fmin
31+
| Bn::Fmod
32+
| Bn::Frexp
33+
| Bn::Ldexp
34+
| Bn::Modf
35+
| Bn::Nextafter
36+
| Bn::Remainder
37+
| Bn::Remquo
38+
| Bn::Rint
39+
| Bn::Round
40+
| Bn::Scalbn
41+
| Bn::Sqrt
42+
| Bn::Trunc => 0,
43+
44+
// Operations that aren't required to be exact, but our implementations are.
45+
Bn::Cbrt if ctx.fn_ident != Id::Cbrt => 0,
46+
Bn::Ilogb => 0,
47+
Bn::Tgamma if ctx.fn_ident != Id::Tgamma => 0,
48+
49+
// Bessel functions have large inaccuracies.
50+
Bn::J0 | Bn::J1 | Bn::Y0 | Bn::Y1 => 8_000_000,
51+
Bn::Jn | Bn::Yn => 1_000,
52+
53+
// For all other operations, specify our implementation's worst case precision.
54+
Bn::Acos => 1,
55+
Bn::Acosh => 4,
56+
Bn::Asin => 1,
57+
Bn::Asinh => 2,
58+
Bn::Atan => 1,
59+
Bn::Atan2 => 1,
60+
Bn::Atanh => 2,
61+
Bn::Cbrt => 1,
62+
Bn::Cos => 1,
63+
Bn::Cosh => 1,
64+
Bn::Erf => 1,
65+
Bn::Erfc => 4,
66+
Bn::Exp => 1,
67+
Bn::Exp10 => 6,
68+
Bn::Exp2 => 1,
69+
Bn::Expm1 => 1,
70+
Bn::Hypot => 1,
71+
Bn::Lgamma | Bn::LgammaR => 16,
72+
Bn::Log => 1,
73+
Bn::Log10 => 1,
74+
Bn::Log1p => 1,
75+
Bn::Log2 => 1,
76+
Bn::Pow => 1,
77+
Bn::Sin => 1,
78+
Bn::Sincos => 1,
79+
Bn::Sinh => 2,
80+
Bn::Tan => 1,
81+
Bn::Tanh => 2,
82+
Bn::Tgamma => 20,
83+
};
84+
85+
// There are some cases where musl's approximation is less accurate than ours. For these
86+
// cases, increase the ULP.
87+
if ctx.basis == Musl {
88+
match ctx.base_name {
89+
Bn::Cosh => ulp = 2,
90+
Bn::Exp10 if usize::BITS < 64 => ulp = 4,
91+
Bn::Lgamma | Bn::LgammaR => ulp = 400,
92+
Bn::Tanh => ulp = 4,
93+
_ if ctx.fn_ident == Id::Sincosf => ulp = 500,
94+
_ if ctx.fn_ident == Id::Tgamma => ulp = 20,
95+
_ => (),
96+
}
5797
}
98+
99+
// In some cases, our implementation is less accurate than musl on i586.
100+
if cfg!(x86_no_sse) {
101+
match ctx.fn_ident {
102+
Id::Log1p | Id::Log1pf => ulp = 2,
103+
Id::Round => ulp = 1,
104+
Id::Tan => ulp = 2,
105+
_ => (),
106+
}
107+
}
108+
109+
ulp
58110
}
59111

60112
/// Don't run further validation on this test case.

0 commit comments

Comments
 (0)