Skip to content

Commit 284a505

Browse files
authored
Merge pull request rust-lang#5 from japaric/ci64
add test infrastructure for f64 functions
2 parents a9bf348 + 7ac406f commit 284a505

File tree

4 files changed

+230
-11
lines changed

4 files changed

+230
-11
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ cf. [rustwasm/team#84](https://github.com/rustwasm/team/issues/84).
9696

9797
### Other functions
9898

99+
- [x] fabs
99100
- [x] fabsf
100101
- [x] scalbnf
101102
- [x] sqrtf

src/fabs.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
use core::u64;
2+
3+
pub fn fabs(x: f64) -> f64 {
4+
f64::from_bits(x.to_bits() & (u64::MAX / 2))
5+
}

src/lib.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
#![deny(warnings)]
22
#![no_std]
33

4+
mod fabs;
45
mod fabsf;
56
mod fmodf;
67
mod powf;
78
mod scalbnf;
89
mod sqrtf;
910

11+
pub use fabs::fabs;
1012
pub use fabsf::fabsf;
1113
pub use fmodf::fmodf;
1214
pub use powf::powf;
@@ -19,6 +21,11 @@ pub fn _eqf(a: u32, b: u32) -> bool {
1921
(a as i32).wrapping_sub(b as i32).abs() <= 1
2022
}
2123

24+
#[doc(hidden)]
25+
pub fn _eq(a: u64, b: u64) -> bool {
26+
(a as i64).wrapping_sub(b as i64).abs() <= 1
27+
}
28+
2229
fn isnanf(x: f32) -> bool {
2330
x.to_bits() & 0x7fffffff > 0x7f800000
2431
}

test-generator/src/main.rs

Lines changed: 217 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,14 @@ use std::error::Error;
1010
use std::fmt::Write as _0;
1111
use std::fs::{self, File};
1212
use std::io::Write as _1;
13-
use std::{i16, u32, u8};
13+
use std::{i16, u16, u32, u64, u8};
1414

1515
use rand::{Rng, SeedableRng, XorShiftRng};
1616

1717
// Number of test cases to generate
1818
const NTESTS: usize = 10_000;
1919

20-
// TODO tweak this function to generate edge cases (zero, infinity, NaN) more often
20+
// TODO tweak these functions to generate edge cases (zero, infinity, NaN) more often
2121
fn f32(rng: &mut XorShiftRng) -> f32 {
2222
let sign = if rng.gen_bool(0.5) { 1 << 31 } else { 0 };
2323
let exponent = (rng.gen_range(0, u8::MAX) as u32) << 23;
@@ -26,13 +26,21 @@ fn f32(rng: &mut XorShiftRng) -> f32 {
2626
f32::from_bits(sign + exponent + mantissa)
2727
}
2828

29+
fn f64(rng: &mut XorShiftRng) -> f64 {
30+
let sign = if rng.gen_bool(0.5) { 1 << 63 } else { 0 };
31+
let exponent = (rng.gen_range(0, u16::MAX) as u64 & ((1 << 11) - 1)) << 52;
32+
let mantissa = rng.gen_range(0, u64::MAX) & ((1 << 52) - 1);
33+
34+
f64::from_bits(sign + exponent + mantissa)
35+
}
36+
2937
// fn(f32) -> f32
3038
macro_rules! f32_f32 {
31-
($($intr:ident,)+) => {
39+
($($intr:ident,)*) => {
3240
fn f32_f32(rng: &mut XorShiftRng) -> Result<(), Box<Error>> {
3341
// MUSL C implementation of the function to test
3442
extern "C" {
35-
$(fn $intr(_: f32) -> f32;)+
43+
$(fn $intr(_: f32) -> f32;)*
3644
}
3745

3846
$(
@@ -78,18 +86,19 @@ macro_rules! f32_f32 {
7886
",
7987
stringify!($intr),
8088
cases)?;
81-
)+
89+
)*
8290

8391
Ok(())
8492
}
8593
}
8694
}
8795

96+
// fn(f32, f32) -> f32
8897
macro_rules! f32f32_f32 {
89-
($($intr:ident,)+) => {
98+
($($intr:ident,)*) => {
9099
fn f32f32_f32(rng: &mut XorShiftRng) -> Result<(), Box<Error>> {
91100
extern "C" {
92-
$(fn $intr(_: f32, _: f32) -> f32;)+
101+
$(fn $intr(_: f32, _: f32) -> f32;)*
93102
}
94103

95104
$(
@@ -137,18 +146,19 @@ macro_rules! f32f32_f32 {
137146
",
138147
stringify!($intr),
139148
cases)?;
140-
)+
149+
)*
141150

142151
Ok(())
143152
}
144153
};
145154
}
146155

156+
// fn(f32, i32) -> f32
147157
macro_rules! f32i32_f32 {
148-
($($intr:ident,)+) => {
158+
($($intr:ident,)*) => {
149159
fn f32i32_f32(rng: &mut XorShiftRng) -> Result<(), Box<Error>> {
150160
extern "C" {
151-
$(fn $intr(_: f32, _: i32) -> f32;)+
161+
$(fn $intr(_: f32, _: i32) -> f32;)*
152162
}
153163

154164
$(
@@ -195,7 +205,185 @@ macro_rules! f32i32_f32 {
195205
",
196206
stringify!($intr),
197207
cases)?;
198-
)+
208+
)*
209+
210+
Ok(())
211+
}
212+
};
213+
}
214+
215+
// fn(f64) -> f64
216+
macro_rules! f64_f64 {
217+
($($intr:ident,)*) => {
218+
fn f64_f64(rng: &mut XorShiftRng) -> Result<(), Box<Error>> {
219+
// MUSL C implementation of the function to test
220+
extern "C" {
221+
$(fn $intr(_: f64) -> f64;)*
222+
}
223+
224+
$(
225+
let mut cases = String::new();
226+
for _ in 0..NTESTS {
227+
let inp = f64(rng);
228+
let out = unsafe { $intr(inp) };
229+
230+
let inp = inp.to_bits();
231+
let out = out.to_bits();
232+
233+
write!(cases, "({}, {})", inp, out).unwrap();
234+
cases.push(',');
235+
}
236+
237+
let mut f = File::create(concat!("tests/", stringify!($intr), ".rs"))?;
238+
write!(f, "
239+
extern crate libm;
240+
241+
#[test]
242+
fn {0}() {{
243+
const CASES: &[(u64, u64)] = &[
244+
{1}
245+
];
246+
247+
for case in CASES {{
248+
let (inp, expected) = *case;
249+
250+
let outf = libm::{0}(f64::from_bits(inp));
251+
let outi = outf.to_bits();
252+
253+
if !((outf.is_nan() && f64::from_bits(expected).is_nan()) ||
254+
libm::_eq(outi, expected)) {{
255+
panic!(
256+
\"input: {{}}, output: {{}}, expected: {{}}\",
257+
inp,
258+
outi,
259+
expected,
260+
);
261+
}}
262+
}}
263+
}}
264+
",
265+
stringify!($intr),
266+
cases)?;
267+
)*
268+
269+
Ok(())
270+
}
271+
}
272+
}
273+
274+
// fn(f64, f64) -> f64
275+
macro_rules! f64f64_f64 {
276+
($($intr:ident,)*) => {
277+
fn f64f64_f64(rng: &mut XorShiftRng) -> Result<(), Box<Error>> {
278+
extern "C" {
279+
$(fn $intr(_: f64, _: f64) -> f64;)*
280+
}
281+
282+
$(
283+
let mut cases = String::new();
284+
for _ in 0..NTESTS {
285+
let i1 = f64(rng);
286+
let i2 = f64(rng);
287+
let out = unsafe { $intr(i1, i2) };
288+
289+
let i1 = i1.to_bits();
290+
let i2 = i2.to_bits();
291+
let out = out.to_bits();
292+
293+
write!(cases, "(({}, {}), {})", i1, i2, out).unwrap();
294+
cases.push(',');
295+
}
296+
297+
let mut f = File::create(concat!("tests/", stringify!($intr), ".rs"))?;
298+
write!(f, "
299+
extern crate libm;
300+
301+
#[test]
302+
fn {0}() {{
303+
const CASES: &[((u64, u64), u64)] = &[
304+
{1}
305+
];
306+
307+
for case in CASES {{
308+
let ((i1, i2), expected) = *case;
309+
310+
let outf = libm::{0}(f64::from_bits(i1), f64::from_bits(i2));
311+
let outi = outf.to_bits();
312+
313+
if !((outf.is_nan() && f64::from_bits(expected).is_nan()) ||
314+
libm::_eq(outi, expected)) {{
315+
panic!(
316+
\"input: {{:?}}, output: {{}}, expected: {{}}\",
317+
(i1, i2),
318+
outi,
319+
expected,
320+
);
321+
}}
322+
}}
323+
}}
324+
",
325+
stringify!($intr),
326+
cases)?;
327+
)*
328+
329+
Ok(())
330+
}
331+
};
332+
}
333+
334+
// fn(f64, i32) -> f64
335+
macro_rules! f64i32_f64 {
336+
($($intr:ident,)*) => {
337+
fn f64i32_f64(rng: &mut XorShiftRng) -> Result<(), Box<Error>> {
338+
extern "C" {
339+
$(fn $intr(_: f64, _: i32) -> f64;)*
340+
}
341+
342+
$(
343+
let mut cases = String::new();
344+
for _ in 0..NTESTS {
345+
let i1 = f64(rng);
346+
let i2 = rng.gen_range(i16::MIN, i16::MAX);
347+
let out = unsafe { $intr(i1, i2 as i32) };
348+
349+
let i1 = i1.to_bits();
350+
let out = out.to_bits();
351+
352+
write!(cases, "(({}, {}), {})", i1, i2, out).unwrap();
353+
cases.push(',');
354+
}
355+
356+
let mut f = File::create(concat!("tests/", stringify!($intr), ".rs"))?;
357+
write!(f, "
358+
extern crate libm;
359+
360+
#[test]
361+
fn {0}() {{
362+
const CASES: &[((u64, i16), u64)] = &[
363+
{1}
364+
];
365+
366+
for case in CASES {{
367+
let ((i1, i2), expected) = *case;
368+
369+
let outf = libm::{0}(f64::from_bits(i1), i2 as i32);
370+
let outi = outf.to_bits();
371+
372+
if !((outf.is_nan() && f64::from_bits(expected).is_nan()) ||
373+
libm::_eq(outi, expected)) {{
374+
panic!(
375+
\"input: {{:?}}, output: {{}}, expected: {{}}\",
376+
(i1, i2),
377+
outi,
378+
expected,
379+
);
380+
}}
381+
}}
382+
}}
383+
",
384+
stringify!($intr),
385+
cases)?;
386+
)*
199387

200388
Ok(())
201389
}
@@ -211,6 +399,9 @@ fn main() -> Result<(), Box<Error>> {
211399
f32_f32(&mut rng)?;
212400
f32f32_f32(&mut rng)?;
213401
f32i32_f32(&mut rng)?;
402+
f64_f64(&mut rng)?;
403+
f64f64_f64(&mut rng)?;
404+
f64i32_f64(&mut rng)?;
214405

215406
Ok(())
216407
}
@@ -233,3 +424,18 @@ f32f32_f32! {
233424
f32i32_f32! {
234425
scalbnf,
235426
}
427+
428+
// With signature `fn(f64) -> f64`
429+
f64_f64! {
430+
fabs,
431+
}
432+
433+
// With signature `fn(f64, f64) -> f64`
434+
f64f64_f64! {
435+
// fmod,
436+
}
437+
438+
// With signature `fn(f64, i32) -> f64`
439+
f64i32_f64! {
440+
// scalbn,
441+
}

0 commit comments

Comments
 (0)