@@ -77,6 +77,7 @@ impl_call!((f64) -> f64: x: x.0);
77
77
impl_call ! ( ( f64 ) -> i32 : x: x. 0 ) ;
78
78
impl_call ! ( ( f32 ) -> i32 : x: x. 0 ) ;
79
79
impl_call ! ( ( f32 , f32 ) -> f32 : x: x. 0 , x. 1 ) ;
80
+ impl_call ! ( ( f32 , f64 ) -> f32 : x: x. 0 , x. 1 ) ;
80
81
impl_call ! ( ( f64 , f64 ) -> f64 : x: x. 0 , x. 1 ) ;
81
82
impl_call ! ( ( f64 , i32 ) -> f64 : x: x. 0 , x. 1 ) ;
82
83
impl_call ! ( ( f32 , i32 ) -> f32 : x: x. 0 , x. 1 ) ;
@@ -85,23 +86,53 @@ impl_call!((i32, f32) -> f32: x: x.0, x.1);
85
86
impl_call ! ( ( f32 , f32 , f32 ) -> f32 : x: x. 0 , x. 1 , x. 2 ) ;
86
87
impl_call ! ( ( f64 , f64 , f64 ) -> f64 : x: x. 0 , x. 1 , x. 2 ) ;
87
88
88
- // Adjust the input of a function.
89
+ pub trait TupleVec {
90
+ type Output ;
91
+ fn get ( & self , i : usize ) -> Self :: Output ;
92
+ }
93
+
94
+ macro_rules! impl_tuple_vec {
95
+ ( ( $( $arg_tys: ty) ,* ) : $self_: ident: $( $xs: expr) ,* ) => {
96
+ impl TupleVec for ( $( Vec <$arg_tys>, ) +) {
97
+ type Output = ( $( $arg_tys, ) +) ;
98
+ fn get( & self , i: usize ) -> Self :: Output {
99
+ let $self_ = self ;
100
+ ( $( $xs[ i] , ) * )
101
+ }
102
+ }
103
+ } ;
104
+ }
105
+
106
+ impl_tuple_vec ! ( ( f32 ) : x: x. 0 ) ;
107
+ impl_tuple_vec ! ( ( f64 ) : x: x. 0 ) ;
108
+ impl_tuple_vec ! ( ( f32 , f32 ) : x: x. 0 , x. 1 ) ;
109
+ impl_tuple_vec ! ( ( f32 , f64 ) : x: x. 0 , x. 1 ) ;
110
+ impl_tuple_vec ! ( ( f64 , f64 ) : x: x. 0 , x. 1 ) ;
111
+ impl_tuple_vec ! ( ( f64 , i32 ) : x: x. 0 , x. 1 ) ;
112
+ impl_tuple_vec ! ( ( f32 , i32 ) : x: x. 0 , x. 1 ) ;
113
+ impl_tuple_vec ! ( ( i32 , f64 ) : x: x. 0 , x. 1 ) ;
114
+ impl_tuple_vec ! ( ( i32 , f32 ) : x: x. 0 , x. 1 ) ;
115
+ impl_tuple_vec ! ( ( f32 , f32 , f32 ) : x: x. 0 , x. 1 , x. 2 ) ;
116
+ impl_tuple_vec ! ( ( f64 , f64 , f64 ) : x: x. 0 , x. 1 , x. 2 ) ;
117
+
118
+ /// Kind of LibmApi - used to handle generating tests
119
+ /// for some functions slightly differently.
120
+ #[ derive( Copy , Clone , Debug , PartialEq ) ]
121
+ pub enum ApiKind {
122
+ Jx ,
123
+ Other ,
124
+ }
125
+
89
126
#[ macro_export]
90
- macro_rules! adjust_input {
91
- ( fn : j1, input : $arg : ident ) => {
92
- adjust_input! ( adjust : $arg )
127
+ macro_rules! get_api_kind {
128
+ ( fn : j1) => {
129
+ $crate :: ApiKind :: Jx
93
130
} ;
94
- ( fn : jn, input : $arg : ident ) => {
95
- adjust_input! ( adjust : $arg )
131
+ ( fn : jn) => {
132
+ $crate :: ApiKind :: Jx
96
133
} ;
97
- ( fn : $id: ident, input: $args: ident) => { } ;
98
- ( adjust: $arg: ident) => {
99
- // First argument to these functions are a number of
100
- // iterations and passing large random numbers takes forever
101
- // to execute, so check if their higher bits are set and
102
- // zero them:
103
- let p = & mut $arg as * mut _ as * mut i32 ;
104
- unsafe { p. write( p. read( ) & 0xffff ) }
134
+ ( fn : $id: ident) => {
135
+ $crate:: ApiKind :: Other
105
136
} ;
106
137
}
107
138
@@ -121,3 +152,100 @@ macro_rules! assert_approx_eq {
121
152
}
122
153
} ;
123
154
}
155
+
156
+ pub trait Toward : Sized {
157
+ fn toward ( self , other : Self , len : usize ) -> Vec < Self > ;
158
+ }
159
+
160
+ macro_rules! impl_toward_f {
161
+ ( $float_ty: ident, $toward_fn: path) => {
162
+ impl Toward for $float_ty {
163
+ fn toward( self , other: Self , len: usize ) -> Vec <Self > {
164
+ let mut vec = Vec :: with_capacity( len) ;
165
+ let mut current = self ;
166
+ vec. push( self ) ;
167
+ for _ in 0 ..=len {
168
+ current = $toward_fn( current, other as _) ;
169
+ vec. push( self ) ;
170
+ if current. to_bits( ) == other. to_bits( ) {
171
+ break ;
172
+ }
173
+ }
174
+ vec
175
+ }
176
+ }
177
+ } ;
178
+ }
179
+ impl_toward_f ! ( f32 , libm:: nextafterf) ;
180
+ impl_toward_f ! ( f64 , libm:: nextafter) ;
181
+
182
+ pub trait RandSeq : Sized {
183
+ fn rand_seq < R : rand:: Rng > ( rng : & mut R , api_kind : ApiKind , len : usize ) -> Vec < Self > ;
184
+ }
185
+
186
+ macro_rules! impl_rand_seq_f {
187
+ ( $float_ty: ident) => {
188
+ impl RandSeq for $float_ty {
189
+ fn rand_seq<R : rand:: Rng >( rng: & mut R , _api_kind: ApiKind , len: usize ) -> Vec <Self > {
190
+ use std:: $float_ty:: * ;
191
+ let mut vec = Vec :: with_capacity( len) ;
192
+
193
+ // These inputs are always tested
194
+ const BOUNDS : [ $float_ty; 9 ] = [
195
+ NAN ,
196
+ INFINITY ,
197
+ NEG_INFINITY ,
198
+ EPSILON ,
199
+ -EPSILON ,
200
+ MAX ,
201
+ MIN ,
202
+ MIN_POSITIVE ,
203
+ -MIN_POSITIVE ,
204
+ ] ;
205
+ vec. extend( & BOUNDS ) ;
206
+ // A range around the inputs is also always tested:
207
+ const NSTEPS : usize = 1_000 ;
208
+ vec. extend( INFINITY . toward( 0. , NSTEPS ) ) ;
209
+ vec. extend( NEG_INFINITY . toward( 0. , NSTEPS ) ) ;
210
+ vec. extend( ( 0. as $float_ty) . toward( MIN_POSITIVE , NSTEPS ) ) ;
211
+ vec. extend( ( 0. as $float_ty) . toward( -MIN_POSITIVE , NSTEPS ) ) ;
212
+
213
+ for i in 0 ..=NSTEPS {
214
+ let dx = 2. / NSTEPS as $float_ty;
215
+ let next = ( -1. as $float_ty) + ( i as $float_ty) * dx;
216
+ vec. push( next) ;
217
+ }
218
+
219
+ // ~NSTEPS * 4
220
+ assert!( len > 2 * 4 * NSTEPS , "len {} !> {}" , len, 2 * 4 * NSTEPS ) ;
221
+ let current_len = vec. len( ) ;
222
+ let remaining_len = len. checked_sub( current_len) . unwrap( ) ;
223
+
224
+ for _ in 0 ..remaining_len {
225
+ let n = rng. gen :: <$float_ty>( ) ;
226
+ vec. push( n) ;
227
+ }
228
+ assert_eq!( vec. len( ) , len) ;
229
+ vec
230
+ }
231
+ }
232
+ } ;
233
+ }
234
+
235
+ impl_rand_seq_f ! ( f32 ) ;
236
+ impl_rand_seq_f ! ( f64 ) ;
237
+
238
+ impl RandSeq for i32 {
239
+ fn rand_seq < R : rand:: Rng > ( rng : & mut R , api_kind : ApiKind , len : usize ) -> Vec < Self > {
240
+ let mut v = Vec :: with_capacity ( len) ;
241
+ for _ in 0 ..len {
242
+ let mut r = rng. gen :: < i32 > ( ) ;
243
+ if let ApiKind :: Jx = api_kind {
244
+ r &= 0xffff ;
245
+ }
246
+ v. push ( r) ;
247
+ }
248
+ assert_eq ! ( v. len( ) , len) ;
249
+ v
250
+ }
251
+ }
0 commit comments