@@ -115,6 +115,8 @@ pub trait StdFloat: Sealed + Sized {
115
115
/// Returns the floating point's fractional value, with its integer part removed.
116
116
#[ must_use = "method returns a new vector and does not mutate the original value" ]
117
117
fn fract ( self ) -> Self ;
118
+
119
+ fn sin ( self ) -> Self ;
118
120
}
119
121
120
122
impl < const N : usize > Sealed for Simd < f32 , N > where LaneCount < N > : SupportedLaneCount { }
@@ -131,6 +133,23 @@ where
131
133
fn fract ( self ) -> Self {
132
134
self - self . trunc ( )
133
135
}
136
+
137
+ /// Calculate the sine of the angle
138
+ #[ inline]
139
+ fn sin ( self ) -> Self {
140
+ #[ allow( non_snake_case) ]
141
+ let RECIP_2PI = Self :: splat ( 0.15915494 ) ;
142
+
143
+ let scaled = self * RECIP_2PI ;
144
+ let x = scaled - scaled. round ( ) ;
145
+ Self :: splat ( -12.26885994095919635608 )
146
+ . mul_add ( x * x, Self :: splat ( 41.21624105096574396575 ) )
147
+ . mul_add ( x * x, Self :: splat ( -76.58672703333290836700 ) )
148
+ . mul_add ( x * x, Self :: splat ( 81.59746095374827019356 ) )
149
+ . mul_add ( x * x, Self :: splat ( -41.34151143437582891705 ) )
150
+ . mul_add ( x * x, Self :: splat ( 6.28318452581127506328 ) )
151
+ * x
152
+ }
134
153
}
135
154
136
155
impl < const N : usize > StdFloat for Simd < f64 , N >
@@ -143,6 +162,11 @@ where
143
162
fn fract ( self ) -> Self {
144
163
self - self . trunc ( )
145
164
}
165
+
166
+ #[ inline]
167
+ fn sin ( self ) -> Self {
168
+ self
169
+ }
146
170
}
147
171
148
172
#[ cfg( test) ]
@@ -161,5 +185,77 @@ mod tests {
161
185
let _xfma = x. mul_add ( x, x) ;
162
186
let _xsqrt = x. sqrt ( ) ;
163
187
let _ = x2. abs ( ) * x2;
188
+ let _ = x. sin ( ) ;
189
+ }
190
+
191
+ macro_rules! test_range {
192
+ (
193
+ min: $min: expr,
194
+ max: $max: expr,
195
+ limit: $limit: expr,
196
+ scalar_fn: $scalar_fn: expr,
197
+ vector_fn: $vector_fn: expr,
198
+ scalar_type: $scalar_type: ty,
199
+ vector_type: $vector_type: ty,
200
+ ) => { {
201
+ const NUM_ITER : usize = 0x10000 ;
202
+ let limit = <$vector_type>:: splat( $limit) ;
203
+ let b = ( ( $max) - ( $min) ) * ( 1.0 / NUM_ITER as $scalar_type) ;
204
+ let a = $min;
205
+ let sf = $scalar_fn;
206
+ let vf = $vector_fn;
207
+ for i in ( 0 ..NUM_ITER / 4 ) {
208
+ let fi = ( i * 4 ) as $scalar_type;
209
+ let x = <$vector_type>:: from_array( [
210
+ ( fi + 0.0 ) * b + a,
211
+ ( fi + 1.0 ) * b + a,
212
+ ( fi + 2.0 ) * b + a,
213
+ ( fi + 3.0 ) * b + a,
214
+ ] ) ;
215
+ let yref = <$vector_type>:: from_array( [ sf( x[ 0 ] ) , sf( x[ 1 ] ) , sf( x[ 2 ] ) , sf( x[ 3 ] ) ] ) ;
216
+ assert!( ( ( vf( x) - yref) . abs( ) . lanes_le( limit) ) . all( ) ) ;
217
+ }
218
+ } } ;
219
+ }
220
+
221
+ #[ test]
222
+ fn sin_f32 ( ) {
223
+ use core:: f32:: consts:: PI ;
224
+ let ulp = ( 2.0_f32 ) . powi ( -23 ) ;
225
+
226
+ // In the range +/- pi/4 the input has 1 ulp of error.
227
+ test_range ! (
228
+ min: -PI /4.0 ,
229
+ max: PI /4.0 ,
230
+ limit: ulp * 1.0 ,
231
+ scalar_fn: |x : f32 | x. sin( ) ,
232
+ vector_fn: |x : f32x4| x. sin( ) ,
233
+ scalar_type: f32 ,
234
+ vector_type: f32x4,
235
+ ) ;
236
+
237
+ // In the range +/- pi/2 the input and output has 2 ulp of error.
238
+ test_range ! (
239
+ min: -PI /2.0 ,
240
+ max: PI /2.0 ,
241
+ limit: ulp * 2.0 ,
242
+ scalar_fn: |x : f32 | x. sin( ) ,
243
+ vector_fn: |x : f32x4| x. sin( ) ,
244
+ scalar_type: f32 ,
245
+ vector_type: f32x4,
246
+ ) ;
247
+
248
+ // In the range +/- pi the input has 2 ulp of error and the output has 5.
249
+ // Note that the scalar sin also has this error but the implementation
250
+ // is different.
251
+ test_range ! (
252
+ min: -PI ,
253
+ max: PI ,
254
+ limit: ulp * 5.0 ,
255
+ scalar_fn: |x : f32 | x. sin( ) ,
256
+ vector_fn: |x : f32x4| x. sin( ) ,
257
+ scalar_type: f32 ,
258
+ vector_type: f32x4,
259
+ ) ;
164
260
}
165
261
}
0 commit comments