Skip to content

Commit f7441e2

Browse files
author
andy-thomason
committed
Move sin() into StdFloat trait.
1 parent ca31165 commit f7441e2

File tree

3 files changed

+96
-22
lines changed

3 files changed

+96
-22
lines changed

crates/core_simd/src/vector/float.rs

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -45,20 +45,6 @@ macro_rules! impl_float_vector {
4545
Self::splat(1.0) / self
4646
}
4747

48-
/// Calculate the sine of the angle
49-
#[inline]
50-
pub fn sin(self) -> Self {
51-
let x = Self::splat(1.0 / (3.14159265358 * 2.0)) * self;
52-
let x = x - x.floor() - 0.5;
53-
Self::splat(12.268859941019306)
54-
.mul_add(x * x, Self::splat(-41.216241051002875))
55-
.mul_add(x * x, Self::splat(76.58672703334098))
56-
.mul_add(x * x, Self::splat(-81.59746095374902))
57-
.mul_add(x * x, Self::splat(41.34151143437585))
58-
.mul_add(x * x, Self::splat(-6.283184525811273))
59-
* x
60-
}
61-
6248
/// Converts each lane from radians to degrees.
6349
#[inline]
6450
#[must_use = "method returns a new vector and does not mutate the original value"]

crates/core_simd/tests/ops_macros.rs

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -397,14 +397,6 @@ macro_rules! impl_float_tests {
397397
)
398398
}
399399

400-
fn sin<const LANES: usize>() {
401-
test_helpers::test_unary_elementwise(
402-
&Vector::<LANES>::sin,
403-
&Scalar::sin,
404-
&|_| true,
405-
)
406-
}
407-
408400
fn to_degrees<const LANES: usize>() {
409401
test_helpers::test_unary_elementwise(
410402
&Vector::<LANES>::to_degrees,

crates/std_float/src/lib.rs

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

120122
impl<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

136155
impl<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

Comments
 (0)