4
4
// NOTE usually the only thing you need to do to test a new math function is to add it to one of the
5
5
// macro invocations found in the bottom of this file.
6
6
7
+ #[ macro_use]
8
+ extern crate itertools;
7
9
extern crate rand;
8
10
9
11
use std:: error:: Error ;
10
12
use std:: fmt:: Write as _0;
11
13
use std:: fs:: { self , File } ;
12
14
use std:: io:: Write as _1;
13
- use std:: { i16, u16, u32, u64, u8} ;
15
+ use std:: { f32 , f64 , i16, u16, u32, u64, u8} ;
14
16
15
17
use rand:: { Rng , SeedableRng , XorShiftRng } ;
16
18
@@ -34,6 +36,30 @@ fn f64(rng: &mut XorShiftRng) -> f64 {
34
36
f64:: from_bits ( sign + exponent + mantissa)
35
37
}
36
38
39
+ const EDGE_CASES32 : & [ f32 ] = & [
40
+ -0. ,
41
+ 0. ,
42
+ f32:: EPSILON ,
43
+ f32:: INFINITY ,
44
+ f32:: MAX ,
45
+ f32:: MIN ,
46
+ f32:: MIN_POSITIVE ,
47
+ f32:: NAN ,
48
+ f32:: NEG_INFINITY ,
49
+ ] ;
50
+
51
+ const EDGE_CASES64 : & [ f64 ] = & [
52
+ -0. ,
53
+ 0. ,
54
+ f64:: EPSILON ,
55
+ f64:: INFINITY ,
56
+ f64:: MAX ,
57
+ f64:: MIN ,
58
+ f64:: MIN_POSITIVE ,
59
+ f64:: NAN ,
60
+ f64:: NEG_INFINITY ,
61
+ ] ;
62
+
37
63
// fn(f32) -> f32
38
64
macro_rules! f32_f32 {
39
65
( $( $intr: ident, ) * ) => {
@@ -45,8 +71,9 @@ macro_rules! f32_f32 {
45
71
46
72
$(
47
73
let mut cases = String :: new( ) ;
48
- for _ in 0 ..NTESTS {
49
- let inp = f32 ( rng) ;
74
+
75
+ // random inputs
76
+ for inp in EDGE_CASES32 . iter( ) . cloned( ) . chain( ( 0 ..NTESTS ) . map( |_| f32 ( rng) ) ) {
50
77
let out = unsafe { $intr( inp) } ;
51
78
52
79
let inp = inp. to_bits( ) ;
@@ -112,11 +139,17 @@ macro_rules! f32f32_f32 {
112
139
$( fn $intr( _: f32 , _: f32 ) -> f32 ; ) *
113
140
}
114
141
142
+ let mut rng2 = rng. clone( ) ;
143
+ let mut rng3 = rng. clone( ) ;
115
144
$(
116
145
let mut cases = String :: new( ) ;
117
- for _ in 0 ..NTESTS {
118
- let i1 = f32 ( rng) ;
119
- let i2 = f32 ( rng) ;
146
+ for ( i1, i2) in iproduct!(
147
+ EDGE_CASES32 . iter( ) . cloned( ) ,
148
+ EDGE_CASES32 . iter( ) . cloned( )
149
+ ) . chain( EDGE_CASES32 . iter( ) . map( |i1| ( * i1, f32 ( rng) ) ) )
150
+ . chain( EDGE_CASES32 . iter( ) . map( |i2| ( f32 ( & mut rng2) , * i2) ) )
151
+ . chain( ( 0 ..NTESTS ) . map( |_| ( f32 ( & mut rng3) , f32 ( & mut rng3) ) ) )
152
+ {
120
153
let out = unsafe { $intr( i1, i2) } ;
121
154
122
155
let i1 = i1. to_bits( ) ;
@@ -186,12 +219,16 @@ macro_rules! f32f32f32_f32 {
186
219
$( fn $intr( _: f32 , _: f32 , _: f32 ) -> f32 ; ) *
187
220
}
188
221
222
+ let mut rng2 = rng. clone( ) ;
189
223
$(
190
224
let mut cases = String :: new( ) ;
191
- for _ in 0 ..NTESTS {
192
- let i1 = f32 ( rng) ;
193
- let i2 = f32 ( rng) ;
194
- let i3 = f32 ( rng) ;
225
+ for ( i1, i2, i3) in iproduct!(
226
+ EDGE_CASES32 . iter( ) . cloned( ) ,
227
+ EDGE_CASES32 . iter( ) . cloned( ) ,
228
+ EDGE_CASES32 . iter( ) . cloned( )
229
+ ) . chain( EDGE_CASES32 . iter( ) . map( |i1| ( * i1, f32 ( rng) , f32 ( rng) ) ) )
230
+ . chain( ( 0 ..NTESTS ) . map( |_| ( f32 ( & mut rng2) , f32 ( & mut rng2) , f32 ( & mut rng2) ) ) )
231
+ {
195
232
let out = unsafe { $intr( i1, i2, i3) } ;
196
233
197
234
let i1 = i1. to_bits( ) ;
@@ -266,10 +303,10 @@ macro_rules! f32i32_f32 {
266
303
$( fn $intr( _: f32 , _: i32 ) -> f32 ; ) *
267
304
}
268
305
306
+ let mut rng2 = rng. clone( ) ;
269
307
$(
270
308
let mut cases = String :: new( ) ;
271
- for _ in 0 ..NTESTS {
272
- let i1 = f32 ( rng) ;
309
+ for i1 in EDGE_CASES32 . iter( ) . cloned( ) . chain( ( 0 ..NTESTS ) . map( |_| f32 ( & mut rng2) ) ) {
273
310
let i2 = rng. gen_range( i16 :: MIN , i16 :: MAX ) ;
274
311
let out = unsafe { $intr( i1, i2 as i32 ) } ;
275
312
@@ -342,8 +379,7 @@ macro_rules! f64_f64 {
342
379
343
380
$(
344
381
let mut cases = String :: new( ) ;
345
- for _ in 0 ..NTESTS {
346
- let inp = f64 ( rng) ;
382
+ for inp in EDGE_CASES64 . iter( ) . cloned( ) . chain( ( 0 ..NTESTS ) . map( |_| f64 ( rng) ) ) {
347
383
let out = unsafe { $intr( inp) } ;
348
384
349
385
let inp = inp. to_bits( ) ;
@@ -412,11 +448,17 @@ macro_rules! f64f64_f64 {
412
448
$( fn $intr( _: f64 , _: f64 ) -> f64 ; ) *
413
449
}
414
450
451
+ let mut rng2 = rng. clone( ) ;
452
+ let mut rng3 = rng. clone( ) ;
415
453
$(
416
454
let mut cases = String :: new( ) ;
417
- for _ in 0 ..NTESTS {
418
- let i1 = f64 ( rng) ;
419
- let i2 = f64 ( rng) ;
455
+ for ( i1, i2) in iproduct!(
456
+ EDGE_CASES64 . iter( ) . cloned( ) ,
457
+ EDGE_CASES64 . iter( ) . cloned( )
458
+ ) . chain( EDGE_CASES64 . iter( ) . map( |i1| ( * i1, f64 ( rng) ) ) )
459
+ . chain( EDGE_CASES64 . iter( ) . map( |i2| ( f64 ( & mut rng2) , * i2) ) )
460
+ . chain( ( 0 ..NTESTS ) . map( |_| ( f64 ( & mut rng3) , f64 ( & mut rng3) ) ) )
461
+ {
420
462
let out = unsafe { $intr( i1, i2) } ;
421
463
422
464
let i1 = i1. to_bits( ) ;
@@ -485,12 +527,16 @@ macro_rules! f64f64f64_f64 {
485
527
$( fn $intr( _: f64 , _: f64 , _: f64 ) -> f64 ; ) *
486
528
}
487
529
530
+ let mut rng2 = rng. clone( ) ;
488
531
$(
489
532
let mut cases = String :: new( ) ;
490
- for _ in 0 ..NTESTS {
491
- let i1 = f64 ( rng) ;
492
- let i2 = f64 ( rng) ;
493
- let i3 = f64 ( rng) ;
533
+ for ( i1, i2, i3) in iproduct!(
534
+ EDGE_CASES64 . iter( ) . cloned( ) ,
535
+ EDGE_CASES64 . iter( ) . cloned( ) ,
536
+ EDGE_CASES64 . iter( ) . cloned( )
537
+ ) . chain( EDGE_CASES64 . iter( ) . map( |i1| ( * i1, f64 ( rng) , f64 ( rng) ) ) )
538
+ . chain( ( 0 ..NTESTS ) . map( |_| ( f64 ( & mut rng2) , f64 ( & mut rng2) , f64 ( & mut rng2) ) ) )
539
+ {
494
540
let out = unsafe { $intr( i1, i2, i3) } ;
495
541
496
542
let i1 = i1. to_bits( ) ;
@@ -565,10 +611,10 @@ macro_rules! f64i32_f64 {
565
611
$( fn $intr( _: f64 , _: i32 ) -> f64 ; ) *
566
612
}
567
613
614
+ let mut rng2 = rng. clone( ) ;
568
615
$(
569
616
let mut cases = String :: new( ) ;
570
- for _ in 0 ..NTESTS {
571
- let i1 = f64 ( rng) ;
617
+ for i1 in EDGE_CASES64 . iter( ) . cloned( ) . chain( ( 0 ..NTESTS ) . map( |_| f64 ( & mut rng2) ) ) {
572
618
let i2 = rng. gen_range( i16 :: MIN , i16 :: MAX ) ;
573
619
let out = unsafe { $intr( i1, i2 as i32 ) } ;
574
620
0 commit comments