@@ -115,6 +115,8 @@ pub trait StdFloat: Sealed + Sized {
115115 /// Returns the floating point's fractional value, with its integer part removed.
116116 #[ must_use = "method returns a new vector and does not mutate the original value" ]
117117 fn fract ( self ) -> Self ;
118+
119+ fn sin ( self ) -> Self ;
118120}
119121
120122impl < const N : usize > Sealed for Simd < f32 , N > where LaneCount < N > : SupportedLaneCount { }
@@ -131,6 +133,23 @@ where
131133 fn fract ( self ) -> Self {
132134 self - self . trunc ( )
133135 }
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+ }
134153}
135154
136155impl < const N : usize > StdFloat for Simd < f64 , N >
@@ -143,6 +162,11 @@ where
143162 fn fract ( self ) -> Self {
144163 self - self . trunc ( )
145164 }
165+
166+ #[ inline]
167+ fn sin ( self ) -> Self {
168+ self
169+ }
146170}
147171
148172#[ cfg( test) ]
@@ -161,5 +185,77 @@ mod tests {
161185 let _xfma = x. mul_add ( x, x) ;
162186 let _xsqrt = x. sqrt ( ) ;
163187 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+ ) ;
164260 }
165261}
0 commit comments