Skip to content

Commit 10ba25f

Browse files
committed
fmaximum,fminimum: Fix incorrect result and add tests
After adding tests, the current implementation for fminimum fails when provided a negative zero and NaN as inputs: ---- math::fminimum_fmaximum_num::tests::fmaximum_num_spec_tests_f64 stdout ---- thread 'math::fminimum_fmaximum_num::tests::fmaximum_num_spec_tests_f64' panicked at libm/src/math/fminimum_fmaximum_num.rs:240:13: fmaximum_num(-0x0p+0, NaN) l: NaN (0x7ff8000000000000) r: -0.0 (0x8000000000000000) ---- math::fminimum_fmaximum_num::tests::fmaximum_num_spec_tests_f32 stdout ---- thread 'math::fminimum_fmaximum_num::tests::fmaximum_num_spec_tests_f32' panicked at libm/src/math/fminimum_fmaximum_num.rs:240:13: fmaximum_num(-0x0p+0, NaN) l: NaN (0x7fc00000) r: -0.0 (0x80000000) Add more thorough spec tests for these functions and correct the implementations. Canonicalization is also moved to a trait method to centralize documentation about what it does and doesn't do.
1 parent 013e06c commit 10ba25f

File tree

11 files changed

+392
-57
lines changed

11 files changed

+392
-57
lines changed

library/compiler-builtins/libm/src/math/fmin_fmax.rs

Lines changed: 116 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -82,22 +82,77 @@ mod tests {
8282
fn fmin_spec_test<F: Float>(f: impl Fn(F, F) -> F) {
8383
let cases = [
8484
(F::ZERO, F::ZERO, F::ZERO),
85-
(F::ONE, F::ONE, F::ONE),
8685
(F::ZERO, F::ONE, F::ZERO),
87-
(F::ONE, F::ZERO, F::ZERO),
8886
(F::ZERO, F::NEG_ONE, F::NEG_ONE),
87+
(F::ZERO, F::INFINITY, F::ZERO),
88+
(F::ZERO, F::NEG_INFINITY, F::NEG_INFINITY),
89+
(F::ZERO, F::NAN, F::ZERO),
90+
(F::ZERO, F::NEG_NAN, F::ZERO),
91+
(F::NEG_ZERO, F::NEG_ZERO, F::NEG_ZERO),
92+
(F::NEG_ZERO, F::ONE, F::NEG_ZERO),
93+
(F::NEG_ZERO, F::NEG_ONE, F::NEG_ONE),
94+
(F::NEG_ZERO, F::INFINITY, F::NEG_ZERO),
95+
(F::NEG_ZERO, F::NEG_INFINITY, F::NEG_INFINITY),
96+
(F::NEG_ZERO, F::NAN, F::NEG_ZERO),
97+
(F::NEG_ZERO, F::NEG_NAN, F::NEG_ZERO),
98+
(F::ONE, F::ZERO, F::ZERO),
99+
(F::ONE, F::NEG_ZERO, F::NEG_ZERO),
100+
(F::ONE, F::ONE, F::ONE),
101+
(F::ONE, F::NEG_ONE, F::NEG_ONE),
102+
(F::ONE, F::INFINITY, F::ONE),
103+
(F::ONE, F::NEG_INFINITY, F::NEG_INFINITY),
104+
(F::ONE, F::NAN, F::ONE),
105+
(F::ONE, F::NEG_NAN, F::ONE),
89106
(F::NEG_ONE, F::ZERO, F::NEG_ONE),
107+
(F::NEG_ONE, F::NEG_ZERO, F::NEG_ONE),
108+
(F::NEG_ONE, F::ONE, F::NEG_ONE),
109+
(F::NEG_ONE, F::NEG_ONE, F::NEG_ONE),
110+
(F::NEG_ONE, F::INFINITY, F::NEG_ONE),
111+
(F::NEG_ONE, F::NEG_INFINITY, F::NEG_INFINITY),
112+
(F::NEG_ONE, F::NAN, F::NEG_ONE),
113+
(F::NEG_ONE, F::NEG_NAN, F::NEG_ONE),
90114
(F::INFINITY, F::ZERO, F::ZERO),
115+
(F::INFINITY, F::NEG_ZERO, F::NEG_ZERO),
116+
(F::INFINITY, F::ONE, F::ONE),
117+
(F::INFINITY, F::NEG_ONE, F::NEG_ONE),
118+
(F::INFINITY, F::INFINITY, F::INFINITY),
119+
(F::INFINITY, F::NEG_INFINITY, F::NEG_INFINITY),
120+
(F::INFINITY, F::NAN, F::INFINITY),
121+
(F::INFINITY, F::NEG_NAN, F::INFINITY),
91122
(F::NEG_INFINITY, F::ZERO, F::NEG_INFINITY),
123+
(F::NEG_INFINITY, F::NEG_ZERO, F::NEG_INFINITY),
124+
(F::NEG_INFINITY, F::ONE, F::NEG_INFINITY),
125+
(F::NEG_INFINITY, F::NEG_ONE, F::NEG_INFINITY),
126+
(F::NEG_INFINITY, F::INFINITY, F::NEG_INFINITY),
127+
(F::NEG_INFINITY, F::NEG_INFINITY, F::NEG_INFINITY),
128+
(F::NEG_INFINITY, F::NAN, F::NEG_INFINITY),
129+
(F::NEG_INFINITY, F::NEG_NAN, F::NEG_INFINITY),
92130
(F::NAN, F::ZERO, F::ZERO),
93-
(F::ZERO, F::NAN, F::ZERO),
131+
(F::NAN, F::NEG_ZERO, F::NEG_ZERO),
132+
(F::NAN, F::ONE, F::ONE),
133+
(F::NAN, F::NEG_ONE, F::NEG_ONE),
134+
(F::NAN, F::INFINITY, F::INFINITY),
135+
(F::NAN, F::NEG_INFINITY, F::NEG_INFINITY),
94136
(F::NAN, F::NAN, F::NAN),
137+
(F::NEG_NAN, F::ZERO, F::ZERO),
138+
(F::NEG_NAN, F::NEG_ZERO, F::NEG_ZERO),
139+
(F::NEG_NAN, F::ONE, F::ONE),
140+
(F::NEG_NAN, F::NEG_ONE, F::NEG_ONE),
141+
(F::NEG_NAN, F::INFINITY, F::INFINITY),
142+
(F::NEG_NAN, F::NEG_INFINITY, F::NEG_INFINITY),
95143
];
96144

97145
for (x, y, res) in cases {
98146
let val = f(x, y);
99147
assert_biteq!(val, res, "fmin({}, {})", Hexf(x), Hexf(y));
100148
}
149+
150+
// Ordering between zeros and NaNs does not matter
151+
assert_eq!(f(F::ZERO, F::NEG_ZERO), F::ZERO);
152+
assert_eq!(f(F::NEG_ZERO, F::ZERO), F::ZERO);
153+
assert!(f(F::NAN, F::NEG_NAN).is_nan());
154+
assert!(f(F::NEG_NAN, F::NAN).is_nan());
155+
assert!(f(F::NEG_NAN, F::NEG_NAN).is_nan());
101156
}
102157

103158
#[test]
@@ -125,22 +180,77 @@ mod tests {
125180
fn fmax_spec_test<F: Float>(f: impl Fn(F, F) -> F) {
126181
let cases = [
127182
(F::ZERO, F::ZERO, F::ZERO),
128-
(F::ONE, F::ONE, F::ONE),
129183
(F::ZERO, F::ONE, F::ONE),
130-
(F::ONE, F::ZERO, F::ONE),
131184
(F::ZERO, F::NEG_ONE, F::ZERO),
185+
(F::ZERO, F::INFINITY, F::INFINITY),
186+
(F::ZERO, F::NEG_INFINITY, F::ZERO),
187+
(F::ZERO, F::NAN, F::ZERO),
188+
(F::ZERO, F::NEG_NAN, F::ZERO),
189+
(F::NEG_ZERO, F::NEG_ZERO, F::NEG_ZERO),
190+
(F::NEG_ZERO, F::ONE, F::ONE),
191+
(F::NEG_ZERO, F::NEG_ONE, F::NEG_ZERO),
192+
(F::NEG_ZERO, F::INFINITY, F::INFINITY),
193+
(F::NEG_ZERO, F::NEG_INFINITY, F::NEG_ZERO),
194+
(F::NEG_ZERO, F::NAN, F::NEG_ZERO),
195+
(F::NEG_ZERO, F::NEG_NAN, F::NEG_ZERO),
196+
(F::ONE, F::ZERO, F::ONE),
197+
(F::ONE, F::NEG_ZERO, F::ONE),
198+
(F::ONE, F::ONE, F::ONE),
199+
(F::ONE, F::NEG_ONE, F::ONE),
200+
(F::ONE, F::INFINITY, F::INFINITY),
201+
(F::ONE, F::NEG_INFINITY, F::ONE),
202+
(F::ONE, F::NAN, F::ONE),
203+
(F::ONE, F::NEG_NAN, F::ONE),
132204
(F::NEG_ONE, F::ZERO, F::ZERO),
205+
(F::NEG_ONE, F::NEG_ZERO, F::NEG_ZERO),
206+
(F::NEG_ONE, F::ONE, F::ONE),
207+
(F::NEG_ONE, F::NEG_ONE, F::NEG_ONE),
208+
(F::NEG_ONE, F::INFINITY, F::INFINITY),
209+
(F::NEG_ONE, F::NEG_INFINITY, F::NEG_ONE),
210+
(F::NEG_ONE, F::NAN, F::NEG_ONE),
211+
(F::NEG_ONE, F::NEG_NAN, F::NEG_ONE),
133212
(F::INFINITY, F::ZERO, F::INFINITY),
213+
(F::INFINITY, F::NEG_ZERO, F::INFINITY),
214+
(F::INFINITY, F::ONE, F::INFINITY),
215+
(F::INFINITY, F::NEG_ONE, F::INFINITY),
216+
(F::INFINITY, F::INFINITY, F::INFINITY),
217+
(F::INFINITY, F::NEG_INFINITY, F::INFINITY),
218+
(F::INFINITY, F::NAN, F::INFINITY),
219+
(F::INFINITY, F::NEG_NAN, F::INFINITY),
134220
(F::NEG_INFINITY, F::ZERO, F::ZERO),
221+
(F::NEG_INFINITY, F::NEG_ZERO, F::NEG_ZERO),
222+
(F::NEG_INFINITY, F::ONE, F::ONE),
223+
(F::NEG_INFINITY, F::NEG_ONE, F::NEG_ONE),
224+
(F::NEG_INFINITY, F::INFINITY, F::INFINITY),
225+
(F::NEG_INFINITY, F::NEG_INFINITY, F::NEG_INFINITY),
226+
(F::NEG_INFINITY, F::NAN, F::NEG_INFINITY),
227+
(F::NEG_INFINITY, F::NEG_NAN, F::NEG_INFINITY),
135228
(F::NAN, F::ZERO, F::ZERO),
136-
(F::ZERO, F::NAN, F::ZERO),
229+
(F::NAN, F::NEG_ZERO, F::NEG_ZERO),
230+
(F::NAN, F::ONE, F::ONE),
231+
(F::NAN, F::NEG_ONE, F::NEG_ONE),
232+
(F::NAN, F::INFINITY, F::INFINITY),
233+
(F::NAN, F::NEG_INFINITY, F::NEG_INFINITY),
137234
(F::NAN, F::NAN, F::NAN),
235+
(F::NEG_NAN, F::ZERO, F::ZERO),
236+
(F::NEG_NAN, F::NEG_ZERO, F::NEG_ZERO),
237+
(F::NEG_NAN, F::ONE, F::ONE),
238+
(F::NEG_NAN, F::NEG_ONE, F::NEG_ONE),
239+
(F::NEG_NAN, F::INFINITY, F::INFINITY),
240+
(F::NEG_NAN, F::NEG_INFINITY, F::NEG_INFINITY),
138241
];
139242

140243
for (x, y, res) in cases {
141244
let val = f(x, y);
142245
assert_biteq!(val, res, "fmax({}, {})", Hexf(x), Hexf(y));
143246
}
247+
248+
// Ordering between zeros and NaNs does not matter
249+
assert_eq!(f(F::ZERO, F::NEG_ZERO), F::ZERO);
250+
assert_eq!(f(F::NEG_ZERO, F::ZERO), F::ZERO);
251+
assert!(f(F::NAN, F::NEG_NAN).is_nan());
252+
assert!(f(F::NEG_NAN, F::NAN).is_nan());
253+
assert!(f(F::NEG_NAN, F::NEG_NAN).is_nan());
144254
}
145255

146256
#[test]

library/compiler-builtins/libm/src/math/fminimum_fmaximum.rs

Lines changed: 116 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -74,24 +74,77 @@ mod tests {
7474
fn fminimum_spec_test<F: Float>(f: impl Fn(F, F) -> F) {
7575
let cases = [
7676
(F::ZERO, F::ZERO, F::ZERO),
77-
(F::ONE, F::ONE, F::ONE),
77+
(F::ZERO, F::NEG_ZERO, F::NEG_ZERO),
7878
(F::ZERO, F::ONE, F::ZERO),
79-
(F::ONE, F::ZERO, F::ZERO),
8079
(F::ZERO, F::NEG_ONE, F::NEG_ONE),
80+
(F::ZERO, F::INFINITY, F::ZERO),
81+
(F::ZERO, F::NEG_INFINITY, F::NEG_INFINITY),
82+
(F::ZERO, F::NAN, F::NAN),
83+
(F::NEG_ZERO, F::ZERO, F::NEG_ZERO),
84+
(F::NEG_ZERO, F::NEG_ZERO, F::NEG_ZERO),
85+
(F::NEG_ZERO, F::ONE, F::NEG_ZERO),
86+
(F::NEG_ZERO, F::NEG_ONE, F::NEG_ONE),
87+
(F::NEG_ZERO, F::INFINITY, F::NEG_ZERO),
88+
(F::NEG_ZERO, F::NEG_INFINITY, F::NEG_INFINITY),
89+
(F::NEG_ZERO, F::NAN, F::NAN),
90+
(F::ONE, F::ZERO, F::ZERO),
91+
(F::ONE, F::NEG_ZERO, F::NEG_ZERO),
92+
(F::ONE, F::ONE, F::ONE),
93+
(F::ONE, F::NEG_ONE, F::NEG_ONE),
94+
(F::ONE, F::INFINITY, F::ONE),
95+
(F::ONE, F::NEG_INFINITY, F::NEG_INFINITY),
96+
(F::ONE, F::NAN, F::NAN),
8197
(F::NEG_ONE, F::ZERO, F::NEG_ONE),
98+
(F::NEG_ONE, F::NEG_ZERO, F::NEG_ONE),
99+
(F::NEG_ONE, F::ONE, F::NEG_ONE),
100+
(F::NEG_ONE, F::NEG_ONE, F::NEG_ONE),
101+
(F::NEG_ONE, F::INFINITY, F::NEG_ONE),
102+
(F::NEG_ONE, F::NEG_INFINITY, F::NEG_INFINITY),
103+
(F::NEG_ONE, F::NAN, F::NAN),
82104
(F::INFINITY, F::ZERO, F::ZERO),
105+
(F::INFINITY, F::NEG_ZERO, F::NEG_ZERO),
106+
(F::INFINITY, F::ONE, F::ONE),
107+
(F::INFINITY, F::NEG_ONE, F::NEG_ONE),
108+
(F::INFINITY, F::INFINITY, F::INFINITY),
109+
(F::INFINITY, F::NEG_INFINITY, F::NEG_INFINITY),
110+
(F::INFINITY, F::NAN, F::NAN),
83111
(F::NEG_INFINITY, F::ZERO, F::NEG_INFINITY),
112+
(F::NEG_INFINITY, F::NEG_ZERO, F::NEG_INFINITY),
113+
(F::NEG_INFINITY, F::ONE, F::NEG_INFINITY),
114+
(F::NEG_INFINITY, F::NEG_ONE, F::NEG_INFINITY),
115+
(F::NEG_INFINITY, F::INFINITY, F::NEG_INFINITY),
116+
(F::NEG_INFINITY, F::NEG_INFINITY, F::NEG_INFINITY),
117+
(F::NEG_INFINITY, F::NAN, F::NAN),
84118
(F::NAN, F::ZERO, F::NAN),
85-
(F::ZERO, F::NAN, F::NAN),
119+
(F::NAN, F::NEG_ZERO, F::NAN),
120+
(F::NAN, F::ONE, F::NAN),
121+
(F::NAN, F::NEG_ONE, F::NAN),
122+
(F::NAN, F::INFINITY, F::NAN),
123+
(F::NAN, F::NEG_INFINITY, F::NAN),
86124
(F::NAN, F::NAN, F::NAN),
87-
(F::ZERO, F::NEG_ZERO, F::NEG_ZERO),
88-
(F::NEG_ZERO, F::ZERO, F::NEG_ZERO),
89125
];
90126

91127
for (x, y, res) in cases {
92128
let val = f(x, y);
93129
assert_biteq!(val, res, "fminimum({}, {})", Hexf(x), Hexf(y));
94130
}
131+
132+
// Ordering between NaNs does not matter
133+
assert!(f(F::NAN, F::NEG_NAN).is_nan());
134+
assert!(f(F::NEG_NAN, F::NAN).is_nan());
135+
assert!(f(F::ZERO, F::NEG_NAN).is_nan());
136+
assert!(f(F::NEG_ZERO, F::NEG_NAN).is_nan());
137+
assert!(f(F::ONE, F::NEG_NAN).is_nan());
138+
assert!(f(F::NEG_ONE, F::NEG_NAN).is_nan());
139+
assert!(f(F::INFINITY, F::NEG_NAN).is_nan());
140+
assert!(f(F::NEG_INFINITY, F::NEG_NAN).is_nan());
141+
assert!(f(F::NEG_NAN, F::ZERO).is_nan());
142+
assert!(f(F::NEG_NAN, F::NEG_ZERO).is_nan());
143+
assert!(f(F::NEG_NAN, F::ONE).is_nan());
144+
assert!(f(F::NEG_NAN, F::NEG_ONE).is_nan());
145+
assert!(f(F::NEG_NAN, F::INFINITY).is_nan());
146+
assert!(f(F::NEG_NAN, F::NEG_INFINITY).is_nan());
147+
assert!(f(F::NEG_NAN, F::NEG_NAN).is_nan());
95148
}
96149

97150
#[test]
@@ -119,24 +172,77 @@ mod tests {
119172
fn fmaximum_spec_test<F: Float>(f: impl Fn(F, F) -> F) {
120173
let cases = [
121174
(F::ZERO, F::ZERO, F::ZERO),
122-
(F::ONE, F::ONE, F::ONE),
175+
(F::ZERO, F::NEG_ZERO, F::ZERO),
123176
(F::ZERO, F::ONE, F::ONE),
124-
(F::ONE, F::ZERO, F::ONE),
125177
(F::ZERO, F::NEG_ONE, F::ZERO),
178+
(F::ZERO, F::INFINITY, F::INFINITY),
179+
(F::ZERO, F::NEG_INFINITY, F::ZERO),
180+
(F::ZERO, F::NAN, F::NAN),
181+
(F::NEG_ZERO, F::ZERO, F::ZERO),
182+
(F::NEG_ZERO, F::NEG_ZERO, F::NEG_ZERO),
183+
(F::NEG_ZERO, F::ONE, F::ONE),
184+
(F::NEG_ZERO, F::NEG_ONE, F::NEG_ZERO),
185+
(F::NEG_ZERO, F::INFINITY, F::INFINITY),
186+
(F::NEG_ZERO, F::NEG_INFINITY, F::NEG_ZERO),
187+
(F::NEG_ZERO, F::NAN, F::NAN),
188+
(F::ONE, F::ZERO, F::ONE),
189+
(F::ONE, F::NEG_ZERO, F::ONE),
190+
(F::ONE, F::ONE, F::ONE),
191+
(F::ONE, F::NEG_ONE, F::ONE),
192+
(F::ONE, F::INFINITY, F::INFINITY),
193+
(F::ONE, F::NEG_INFINITY, F::ONE),
194+
(F::ONE, F::NAN, F::NAN),
126195
(F::NEG_ONE, F::ZERO, F::ZERO),
196+
(F::NEG_ONE, F::NEG_ZERO, F::NEG_ZERO),
197+
(F::NEG_ONE, F::ONE, F::ONE),
198+
(F::NEG_ONE, F::NEG_ONE, F::NEG_ONE),
199+
(F::NEG_ONE, F::INFINITY, F::INFINITY),
200+
(F::NEG_ONE, F::NEG_INFINITY, F::NEG_ONE),
201+
(F::NEG_ONE, F::NAN, F::NAN),
127202
(F::INFINITY, F::ZERO, F::INFINITY),
203+
(F::INFINITY, F::NEG_ZERO, F::INFINITY),
204+
(F::INFINITY, F::ONE, F::INFINITY),
205+
(F::INFINITY, F::NEG_ONE, F::INFINITY),
206+
(F::INFINITY, F::INFINITY, F::INFINITY),
207+
(F::INFINITY, F::NEG_INFINITY, F::INFINITY),
208+
(F::INFINITY, F::NAN, F::NAN),
128209
(F::NEG_INFINITY, F::ZERO, F::ZERO),
210+
(F::NEG_INFINITY, F::NEG_ZERO, F::NEG_ZERO),
211+
(F::NEG_INFINITY, F::ONE, F::ONE),
212+
(F::NEG_INFINITY, F::NEG_ONE, F::NEG_ONE),
213+
(F::NEG_INFINITY, F::INFINITY, F::INFINITY),
214+
(F::NEG_INFINITY, F::NEG_INFINITY, F::NEG_INFINITY),
215+
(F::NEG_INFINITY, F::NAN, F::NAN),
129216
(F::NAN, F::ZERO, F::NAN),
130-
(F::ZERO, F::NAN, F::NAN),
217+
(F::NAN, F::NEG_ZERO, F::NAN),
218+
(F::NAN, F::ONE, F::NAN),
219+
(F::NAN, F::NEG_ONE, F::NAN),
220+
(F::NAN, F::INFINITY, F::NAN),
221+
(F::NAN, F::NEG_INFINITY, F::NAN),
131222
(F::NAN, F::NAN, F::NAN),
132-
(F::ZERO, F::NEG_ZERO, F::ZERO),
133-
(F::NEG_ZERO, F::ZERO, F::ZERO),
134223
];
135224

136225
for (x, y, res) in cases {
137226
let val = f(x, y);
138227
assert_biteq!(val, res, "fmaximum({}, {})", Hexf(x), Hexf(y));
139228
}
229+
230+
// Ordering between NaNs does not matter
231+
assert!(f(F::NAN, F::NEG_NAN).is_nan());
232+
assert!(f(F::NEG_NAN, F::NAN).is_nan());
233+
assert!(f(F::ZERO, F::NEG_NAN).is_nan());
234+
assert!(f(F::NEG_ZERO, F::NEG_NAN).is_nan());
235+
assert!(f(F::ONE, F::NEG_NAN).is_nan());
236+
assert!(f(F::NEG_ONE, F::NEG_NAN).is_nan());
237+
assert!(f(F::INFINITY, F::NEG_NAN).is_nan());
238+
assert!(f(F::NEG_INFINITY, F::NEG_NAN).is_nan());
239+
assert!(f(F::NEG_NAN, F::ZERO).is_nan());
240+
assert!(f(F::NEG_NAN, F::NEG_ZERO).is_nan());
241+
assert!(f(F::NEG_NAN, F::ONE).is_nan());
242+
assert!(f(F::NEG_NAN, F::NEG_ONE).is_nan());
243+
assert!(f(F::NEG_NAN, F::INFINITY).is_nan());
244+
assert!(f(F::NEG_NAN, F::NEG_INFINITY).is_nan());
245+
assert!(f(F::NEG_NAN, F::NEG_NAN).is_nan());
140246
}
141247

142248
#[test]

0 commit comments

Comments
 (0)