Skip to content

Commit 9322bbd

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.
1 parent 4f943d4 commit 9322bbd

File tree

8 files changed

+377
-45
lines changed

8 files changed

+377
-45
lines changed

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),
143+
(F::NEG_NAN, F::NEG_NAN, F::NEG_NAN),
95144
];
96145

97146
for (x, y, res) in cases {
98147
let val = f(x, y);
99148
assert_biteq!(val, res, "fmin({}, {})", Hexf(x), Hexf(y));
100149
}
150+
151+
// Ordering between zeros and NaNs does not matter
152+
assert_eq!(f(F::ZERO, F::NEG_ZERO), F::ZERO);
153+
assert_eq!(f(F::NEG_ZERO, F::ZERO), F::ZERO);
154+
assert!(f(F::NAN, F::NEG_NAN).is_nan());
155+
assert!(f(F::NEG_NAN, F::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),
241+
(F::NEG_NAN, F::NEG_NAN, F::NEG_NAN),
138242
];
139243

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

146256
#[test]

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::ZERO, F::NEG_NAN, F::NEG_NAN),
84+
(F::NEG_ZERO, F::ZERO, F::NEG_ZERO),
85+
(F::NEG_ZERO, F::NEG_ZERO, F::NEG_ZERO),
86+
(F::NEG_ZERO, F::ONE, F::NEG_ZERO),
87+
(F::NEG_ZERO, F::NEG_ONE, F::NEG_ONE),
88+
(F::NEG_ZERO, F::INFINITY, F::NEG_ZERO),
89+
(F::NEG_ZERO, F::NEG_INFINITY, F::NEG_INFINITY),
90+
(F::NEG_ZERO, F::NAN, F::NAN),
91+
(F::NEG_ZERO, F::NEG_NAN, F::NEG_NAN),
92+
(F::ONE, F::ZERO, F::ZERO),
93+
(F::ONE, F::NEG_ZERO, F::NEG_ZERO),
94+
(F::ONE, F::ONE, F::ONE),
95+
(F::ONE, F::NEG_ONE, F::NEG_ONE),
96+
(F::ONE, F::INFINITY, F::ONE),
97+
(F::ONE, F::NEG_INFINITY, F::NEG_INFINITY),
98+
(F::ONE, F::NAN, F::NAN),
99+
(F::ONE, F::NEG_NAN, F::NEG_NAN),
81100
(F::NEG_ONE, F::ZERO, F::NEG_ONE),
101+
(F::NEG_ONE, F::NEG_ZERO, F::NEG_ONE),
102+
(F::NEG_ONE, F::ONE, F::NEG_ONE),
103+
(F::NEG_ONE, F::NEG_ONE, F::NEG_ONE),
104+
(F::NEG_ONE, F::INFINITY, F::NEG_ONE),
105+
(F::NEG_ONE, F::NEG_INFINITY, F::NEG_INFINITY),
106+
(F::NEG_ONE, F::NAN, F::NAN),
107+
(F::NEG_ONE, F::NEG_NAN, F::NEG_NAN),
82108
(F::INFINITY, F::ZERO, F::ZERO),
109+
(F::INFINITY, F::NEG_ZERO, F::NEG_ZERO),
110+
(F::INFINITY, F::ONE, F::ONE),
111+
(F::INFINITY, F::NEG_ONE, F::NEG_ONE),
112+
(F::INFINITY, F::INFINITY, F::INFINITY),
113+
(F::INFINITY, F::NEG_INFINITY, F::NEG_INFINITY),
114+
(F::INFINITY, F::NAN, F::NAN),
115+
(F::INFINITY, F::NEG_NAN, F::NEG_NAN),
83116
(F::NEG_INFINITY, F::ZERO, F::NEG_INFINITY),
117+
(F::NEG_INFINITY, F::NEG_ZERO, F::NEG_INFINITY),
118+
(F::NEG_INFINITY, F::ONE, F::NEG_INFINITY),
119+
(F::NEG_INFINITY, F::NEG_ONE, F::NEG_INFINITY),
120+
(F::NEG_INFINITY, F::INFINITY, F::NEG_INFINITY),
121+
(F::NEG_INFINITY, F::NEG_INFINITY, F::NEG_INFINITY),
122+
(F::NEG_INFINITY, F::NAN, F::NAN),
123+
(F::NEG_INFINITY, F::NEG_NAN, F::NEG_NAN),
84124
(F::NAN, F::ZERO, F::NAN),
85-
(F::ZERO, F::NAN, F::NAN),
125+
(F::NAN, F::NEG_ZERO, F::NAN),
126+
(F::NAN, F::ONE, F::NAN),
127+
(F::NAN, F::NEG_ONE, F::NAN),
128+
(F::NAN, F::INFINITY, F::NAN),
129+
(F::NAN, F::NEG_INFINITY, F::NAN),
86130
(F::NAN, F::NAN, F::NAN),
87-
(F::ZERO, F::NEG_ZERO, F::NEG_ZERO),
88-
(F::NEG_ZERO, F::ZERO, F::NEG_ZERO),
131+
(F::NEG_NAN, F::ZERO, F::NEG_NAN),
132+
(F::NEG_NAN, F::NEG_ZERO, F::NEG_NAN),
133+
(F::NEG_NAN, F::ONE, F::NEG_NAN),
134+
(F::NEG_NAN, F::NEG_ONE, F::NEG_NAN),
135+
(F::NEG_NAN, F::INFINITY, F::NEG_NAN),
136+
(F::NEG_NAN, F::NEG_INFINITY, F::NEG_NAN),
137+
(F::NEG_NAN, F::NEG_NAN, F::NEG_NAN),
89138
];
90139

91140
for (x, y, res) in cases {
92141
let val = f(x, y);
93142
assert_biteq!(val, res, "fminimum({}, {})", Hexf(x), Hexf(y));
94143
}
144+
145+
// Ordering between NaNs does not matter
146+
assert!(f(F::NAN, F::NEG_NAN).is_nan());
147+
assert!(f(F::NEG_NAN, F::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::ZERO, F::NEG_NAN, F::NEG_NAN),
182+
(F::NEG_ZERO, F::ZERO, F::ZERO),
183+
(F::NEG_ZERO, F::NEG_ZERO, F::NEG_ZERO),
184+
(F::NEG_ZERO, F::ONE, F::ONE),
185+
(F::NEG_ZERO, F::NEG_ONE, F::NEG_ZERO),
186+
(F::NEG_ZERO, F::INFINITY, F::INFINITY),
187+
(F::NEG_ZERO, F::NEG_INFINITY, F::NEG_ZERO),
188+
(F::NEG_ZERO, F::NAN, F::NAN),
189+
(F::NEG_ZERO, F::NEG_NAN, F::NEG_NAN),
190+
(F::ONE, F::ZERO, F::ONE),
191+
(F::ONE, F::NEG_ZERO, F::ONE),
192+
(F::ONE, F::ONE, F::ONE),
193+
(F::ONE, F::NEG_ONE, F::ONE),
194+
(F::ONE, F::INFINITY, F::INFINITY),
195+
(F::ONE, F::NEG_INFINITY, F::ONE),
196+
(F::ONE, F::NAN, F::NAN),
197+
(F::ONE, F::NEG_NAN, F::NEG_NAN),
126198
(F::NEG_ONE, F::ZERO, F::ZERO),
199+
(F::NEG_ONE, F::NEG_ZERO, F::NEG_ZERO),
200+
(F::NEG_ONE, F::ONE, F::ONE),
201+
(F::NEG_ONE, F::NEG_ONE, F::NEG_ONE),
202+
(F::NEG_ONE, F::INFINITY, F::INFINITY),
203+
(F::NEG_ONE, F::NEG_INFINITY, F::NEG_ONE),
204+
(F::NEG_ONE, F::NAN, F::NAN),
205+
(F::NEG_ONE, F::NEG_NAN, F::NEG_NAN),
127206
(F::INFINITY, F::ZERO, F::INFINITY),
207+
(F::INFINITY, F::NEG_ZERO, F::INFINITY),
208+
(F::INFINITY, F::ONE, F::INFINITY),
209+
(F::INFINITY, F::NEG_ONE, F::INFINITY),
210+
(F::INFINITY, F::INFINITY, F::INFINITY),
211+
(F::INFINITY, F::NEG_INFINITY, F::INFINITY),
212+
(F::INFINITY, F::NAN, F::NAN),
213+
(F::INFINITY, F::NEG_NAN, F::NEG_NAN),
128214
(F::NEG_INFINITY, F::ZERO, F::ZERO),
215+
(F::NEG_INFINITY, F::NEG_ZERO, F::NEG_ZERO),
216+
(F::NEG_INFINITY, F::ONE, F::ONE),
217+
(F::NEG_INFINITY, F::NEG_ONE, F::NEG_ONE),
218+
(F::NEG_INFINITY, F::INFINITY, F::INFINITY),
219+
(F::NEG_INFINITY, F::NEG_INFINITY, F::NEG_INFINITY),
220+
(F::NEG_INFINITY, F::NAN, F::NAN),
221+
(F::NEG_INFINITY, F::NEG_NAN, F::NEG_NAN),
129222
(F::NAN, F::ZERO, F::NAN),
130-
(F::ZERO, F::NAN, F::NAN),
223+
(F::NAN, F::NEG_ZERO, F::NAN),
224+
(F::NAN, F::ONE, F::NAN),
225+
(F::NAN, F::NEG_ONE, F::NAN),
226+
(F::NAN, F::INFINITY, F::NAN),
227+
(F::NAN, F::NEG_INFINITY, F::NAN),
131228
(F::NAN, F::NAN, F::NAN),
132-
(F::ZERO, F::NEG_ZERO, F::ZERO),
133-
(F::NEG_ZERO, F::ZERO, F::ZERO),
229+
(F::NEG_NAN, F::ZERO, F::NEG_NAN),
230+
(F::NEG_NAN, F::NEG_ZERO, F::NEG_NAN),
231+
(F::NEG_NAN, F::ONE, F::NEG_NAN),
232+
(F::NEG_NAN, F::NEG_ONE, F::NEG_NAN),
233+
(F::NEG_NAN, F::INFINITY, F::NEG_NAN),
234+
(F::NEG_NAN, F::NEG_INFINITY, F::NEG_NAN),
235+
(F::NEG_NAN, F::NEG_NAN, F::NEG_NAN),
134236
];
135237

136238
for (x, y, res) in cases {
137239
let val = f(x, y);
138240
assert_biteq!(val, res, "fmaximum({}, {})", Hexf(x), Hexf(y));
139241
}
242+
243+
// Ordering between NaNs does not matter
244+
assert!(f(F::NAN, F::NEG_NAN).is_nan());
245+
assert!(f(F::NEG_NAN, F::NAN).is_nan());
140246
}
141247

142248
#[test]

0 commit comments

Comments
 (0)