aboutsummaryrefslogtreecommitdiff
path: root/std/math/sin.zig
diff options
context:
space:
mode:
Diffstat (limited to 'std/math/sin.zig')
-rw-r--r--std/math/sin.zig160
1 files changed, 52 insertions, 108 deletions
diff --git a/std/math/sin.zig b/std/math/sin.zig
index e25b8a292b..f21db4054e 100644
--- a/std/math/sin.zig
+++ b/std/math/sin.zig
@@ -1,19 +1,24 @@
-// Special Cases:
+// Ported from go, which is licensed under a BSD-3 license.
+// https://golang.org/LICENSE
//
-// - sin(+-0) = +-0
-// - sin(+-inf) = nan
-// - sin(nan) = nan
+// https://golang.org/src/math/sin.go
const builtin = @import("builtin");
const std = @import("../std.zig");
const math = std.math;
const expect = std.testing.expect;
+/// Returns the sine of the radian value x.
+///
+/// Special Cases:
+/// - sin(+-0) = +-0
+/// - sin(+-inf) = nan
+/// - sin(nan) = nan
pub fn sin(x: var) @typeOf(x) {
const T = @typeOf(x);
return switch (T) {
- f32 => sin32(x),
- f64 => sin64(x),
+ f32 => sin_(T, x),
+ f64 => sin_(T, x),
else => @compileError("sin not implemented for " ++ @typeName(T)),
};
}
@@ -34,83 +39,27 @@ const C3 = 2.48015872888517045348E-5;
const C4 = -1.38888888888730564116E-3;
const C5 = 4.16666666666665929218E-2;
-// NOTE: This is taken from the go stdlib. The musl implementation is much more complex.
-//
-// This may have slight differences on some edge cases and may need to replaced if so.
-fn sin32(x_: f32) f32 {
- const pi4a = 7.85398125648498535156e-1;
- const pi4b = 3.77489470793079817668E-8;
- const pi4c = 2.69515142907905952645E-15;
- const m4pi = 1.273239544735162542821171882678754627704620361328125;
-
- var x = x_;
- if (x == 0 or math.isNan(x)) {
- return x;
- }
- if (math.isInf(x)) {
- return math.nan(f32);
- }
-
- var sign = false;
- if (x < 0) {
- x = -x;
- sign = true;
- }
-
- var y = math.floor(x * m4pi);
- var j = @floatToInt(i64, y);
-
- if (j & 1 == 1) {
- j += 1;
- y += 1;
- }
+const pi4a = 7.85398125648498535156e-1;
+const pi4b = 3.77489470793079817668E-8;
+const pi4c = 2.69515142907905952645E-15;
+const m4pi = 1.273239544735162542821171882678754627704620361328125;
- j &= 7;
- if (j > 3) {
- j -= 4;
- sign = !sign;
- }
-
- const z = ((x - y * pi4a) - y * pi4b) - y * pi4c;
- const w = z * z;
-
- const r = r: {
- if (j == 1 or j == 2) {
- break :r 1.0 - 0.5 * w + w * w * (C5 + w * (C4 + w * (C3 + w * (C2 + w * (C1 + w * C0)))));
- } else {
- break :r z + z * w * (S5 + w * (S4 + w * (S3 + w * (S2 + w * (S1 + w * S0)))));
- }
- };
-
- if (sign) {
- return -r;
- } else {
- return r;
- }
-}
-
-fn sin64(x_: f64) f64 {
- const pi4a = 7.85398125648498535156e-1;
- const pi4b = 3.77489470793079817668E-8;
- const pi4c = 2.69515142907905952645E-15;
- const m4pi = 1.273239544735162542821171882678754627704620361328125;
+fn sin_(comptime T: type, x_: T) T {
+ const I = @IntType(true, T.bit_count);
var x = x_;
if (x == 0 or math.isNan(x)) {
return x;
}
if (math.isInf(x)) {
- return math.nan(f64);
+ return math.nan(T);
}
- var sign = false;
- if (x < 0) {
- x = -x;
- sign = true;
- }
+ var sign = x < 0;
+ x = math.fabs(x);
var y = math.floor(x * m4pi);
- var j = @floatToInt(i64, y);
+ var j = @floatToInt(I, y);
if (j & 1 == 1) {
j += 1;
@@ -126,61 +75,56 @@ fn sin64(x_: f64) f64 {
const z = ((x - y * pi4a) - y * pi4b) - y * pi4c;
const w = z * z;
- const r = r: {
- if (j == 1 or j == 2) {
- break :r 1.0 - 0.5 * w + w * w * (C5 + w * (C4 + w * (C3 + w * (C2 + w * (C1 + w * C0)))));
- } else {
- break :r z + z * w * (S5 + w * (S4 + w * (S3 + w * (S2 + w * (S1 + w * S0)))));
- }
- };
+ const r = if (j == 1 or j == 2)
+ 1.0 - 0.5 * w + w * w * (C5 + w * (C4 + w * (C3 + w * (C2 + w * (C1 + w * C0)))))
+ else
+ z + z * w * (S5 + w * (S4 + w * (S3 + w * (S2 + w * (S1 + w * S0)))));
- if (sign) {
- return -r;
- } else {
- return r;
- }
+ return if (sign) -r else r;
}
test "math.sin" {
- expect(sin(f32(0.0)) == sin32(0.0));
- expect(sin(f64(0.0)) == sin64(0.0));
+ expect(sin(f32(0.0)) == sin_(f32, 0.0));
+ expect(sin(f64(0.0)) == sin_(f64, 0.0));
expect(comptime (math.sin(f64(2))) == math.sin(f64(2)));
}
test "math.sin32" {
const epsilon = 0.000001;
- expect(math.approxEq(f32, sin32(0.0), 0.0, epsilon));
- expect(math.approxEq(f32, sin32(0.2), 0.198669, epsilon));
- expect(math.approxEq(f32, sin32(0.8923), 0.778517, epsilon));
- expect(math.approxEq(f32, sin32(1.5), 0.997495, epsilon));
- expect(math.approxEq(f32, sin32(37.45), -0.246544, epsilon));
- expect(math.approxEq(f32, sin32(89.123), 0.916166, epsilon));
+ expect(math.approxEq(f32, sin_(f32, 0.0), 0.0, epsilon));
+ expect(math.approxEq(f32, sin_(f32, 0.2), 0.198669, epsilon));
+ expect(math.approxEq(f32, sin_(f32, 0.8923), 0.778517, epsilon));
+ expect(math.approxEq(f32, sin_(f32, 1.5), 0.997495, epsilon));
+ expect(math.approxEq(f32, sin_(f32, -1.5), -0.997495, epsilon));
+ expect(math.approxEq(f32, sin_(f32, 37.45), -0.246544, epsilon));
+ expect(math.approxEq(f32, sin_(f32, 89.123), 0.916166, epsilon));
}
test "math.sin64" {
const epsilon = 0.000001;
- expect(math.approxEq(f64, sin64(0.0), 0.0, epsilon));
- expect(math.approxEq(f64, sin64(0.2), 0.198669, epsilon));
- expect(math.approxEq(f64, sin64(0.8923), 0.778517, epsilon));
- expect(math.approxEq(f64, sin64(1.5), 0.997495, epsilon));
- expect(math.approxEq(f64, sin64(37.45), -0.246543, epsilon));
- expect(math.approxEq(f64, sin64(89.123), 0.916166, epsilon));
+ expect(math.approxEq(f64, sin_(f64, 0.0), 0.0, epsilon));
+ expect(math.approxEq(f64, sin_(f64, 0.2), 0.198669, epsilon));
+ expect(math.approxEq(f64, sin_(f64, 0.8923), 0.778517, epsilon));
+ expect(math.approxEq(f64, sin_(f64, 1.5), 0.997495, epsilon));
+ expect(math.approxEq(f64, sin_(f64, -1.5), -0.997495, epsilon));
+ expect(math.approxEq(f64, sin_(f64, 37.45), -0.246543, epsilon));
+ expect(math.approxEq(f64, sin_(f64, 89.123), 0.916166, epsilon));
}
test "math.sin32.special" {
- expect(sin32(0.0) == 0.0);
- expect(sin32(-0.0) == -0.0);
- expect(math.isNan(sin32(math.inf(f32))));
- expect(math.isNan(sin32(-math.inf(f32))));
- expect(math.isNan(sin32(math.nan(f32))));
+ expect(sin_(f32, 0.0) == 0.0);
+ expect(sin_(f32, -0.0) == -0.0);
+ expect(math.isNan(sin_(f32, math.inf(f32))));
+ expect(math.isNan(sin_(f32, -math.inf(f32))));
+ expect(math.isNan(sin_(f32, math.nan(f32))));
}
test "math.sin64.special" {
- expect(sin64(0.0) == 0.0);
- expect(sin64(-0.0) == -0.0);
- expect(math.isNan(sin64(math.inf(f64))));
- expect(math.isNan(sin64(-math.inf(f64))));
- expect(math.isNan(sin64(math.nan(f64))));
+ expect(sin_(f64, 0.0) == 0.0);
+ expect(sin_(f64, -0.0) == -0.0);
+ expect(math.isNan(sin_(f64, math.inf(f64))));
+ expect(math.isNan(sin_(f64, -math.inf(f64))));
+ expect(math.isNan(sin_(f64, math.nan(f64))));
}