2017-06-20 04:01:04 -07:00
|
|
|
// Special Cases:
|
|
|
|
//
|
|
|
|
// - cos(+-inf) = nan
|
|
|
|
// - cos(nan) = nan
|
|
|
|
|
2017-10-14 23:04:21 -07:00
|
|
|
const builtin = @import("builtin");
|
2017-12-23 19:08:53 -08:00
|
|
|
const std = @import("../index.zig");
|
|
|
|
const math = std.math;
|
|
|
|
const assert = std.debug.assert;
|
2017-06-16 01:26:10 -07:00
|
|
|
|
2018-01-25 01:10:11 -08:00
|
|
|
pub fn cos(x: var) @typeOf(x) {
|
2017-06-16 01:26:10 -07:00
|
|
|
const T = @typeOf(x);
|
2017-12-21 21:50:30 -08:00
|
|
|
return switch (T) {
|
2017-12-22 10:14:07 -08:00
|
|
|
f32 => cos32(x),
|
|
|
|
f64 => cos64(x),
|
2017-06-16 01:26:10 -07:00
|
|
|
else => @compileError("cos not implemented for " ++ @typeName(T)),
|
2017-12-21 21:50:30 -08:00
|
|
|
};
|
2017-06-16 01:26:10 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// sin polynomial coefficients
|
2018-05-09 21:29:49 -07:00
|
|
|
const S0 = 1.58962301576546568060E-10;
|
2017-06-16 01:26:10 -07:00
|
|
|
const S1 = -2.50507477628578072866E-8;
|
2018-05-09 21:29:49 -07:00
|
|
|
const S2 = 2.75573136213857245213E-6;
|
2017-06-16 01:26:10 -07:00
|
|
|
const S3 = -1.98412698295895385996E-4;
|
2018-05-09 21:29:49 -07:00
|
|
|
const S4 = 8.33333333332211858878E-3;
|
2017-06-16 01:26:10 -07:00
|
|
|
const S5 = -1.66666666666666307295E-1;
|
|
|
|
|
|
|
|
// cos polynomial coeffiecients
|
|
|
|
const C0 = -1.13585365213876817300E-11;
|
2018-05-09 21:29:49 -07:00
|
|
|
const C1 = 2.08757008419747316778E-9;
|
2017-06-16 01:26:10 -07:00
|
|
|
const C2 = -2.75573141792967388112E-7;
|
2018-05-09 21:29:49 -07:00
|
|
|
const C3 = 2.48015872888517045348E-5;
|
2017-06-16 01:26:10 -07:00
|
|
|
const C4 = -1.38888888888730564116E-3;
|
2018-05-09 21:29:49 -07:00
|
|
|
const C5 = 4.16666666666665929218E-2;
|
2017-06-16 01:26:10 -07:00
|
|
|
|
|
|
|
// 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.
|
2018-01-25 01:10:11 -08:00
|
|
|
fn cos32(x_: f32) f32 {
|
2017-06-17 19:16:04 -07:00
|
|
|
@setFloatMode(this, @import("builtin").FloatMode.Strict);
|
|
|
|
|
2017-06-16 01:26:10 -07:00
|
|
|
const pi4a = 7.85398125648498535156e-1;
|
|
|
|
const pi4b = 3.77489470793079817668E-8;
|
|
|
|
const pi4c = 2.69515142907905952645E-15;
|
|
|
|
const m4pi = 1.273239544735162542821171882678754627704620361328125;
|
|
|
|
|
|
|
|
var x = x_;
|
|
|
|
if (math.isNan(x) or math.isInf(x)) {
|
|
|
|
return math.nan(f32);
|
|
|
|
}
|
|
|
|
|
|
|
|
var sign = false;
|
|
|
|
if (x < 0) {
|
|
|
|
x = -x;
|
|
|
|
}
|
|
|
|
|
|
|
|
var y = math.floor(x * m4pi);
|
2018-06-16 23:57:07 -07:00
|
|
|
var j = @floatToInt(i64, y);
|
2017-06-16 01:26:10 -07:00
|
|
|
|
|
|
|
if (j & 1 == 1) {
|
|
|
|
j += 1;
|
|
|
|
y += 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
j &= 7;
|
|
|
|
if (j > 3) {
|
|
|
|
j -= 4;
|
|
|
|
sign = !sign;
|
|
|
|
}
|
|
|
|
if (j > 1) {
|
|
|
|
sign = !sign;
|
|
|
|
}
|
|
|
|
|
|
|
|
const z = ((x - y * pi4a) - y * pi4b) - y * pi4c;
|
|
|
|
const w = z * z;
|
|
|
|
|
2017-12-21 21:50:30 -08:00
|
|
|
const r = r: {
|
2017-06-16 01:26:10 -07:00
|
|
|
if (j == 1 or j == 2) {
|
2017-12-21 21:50:30 -08:00
|
|
|
break :r z + z * w * (S5 + w * (S4 + w * (S3 + w * (S2 + w * (S1 + w * S0)))));
|
2017-06-16 01:26:10 -07:00
|
|
|
} else {
|
2017-12-21 21:50:30 -08:00
|
|
|
break :r 1.0 - 0.5 * w + w * w * (C5 + w * (C4 + w * (C3 + w * (C2 + w * (C1 + w * C0)))));
|
2017-06-16 01:26:10 -07:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
if (sign) {
|
2017-12-21 21:50:30 -08:00
|
|
|
return -r;
|
2017-06-16 01:26:10 -07:00
|
|
|
} else {
|
2017-12-21 21:50:30 -08:00
|
|
|
return r;
|
2017-06-16 01:26:10 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-01-25 01:10:11 -08:00
|
|
|
fn cos64(x_: f64) f64 {
|
2017-06-16 01:26:10 -07:00
|
|
|
const pi4a = 7.85398125648498535156e-1;
|
|
|
|
const pi4b = 3.77489470793079817668E-8;
|
|
|
|
const pi4c = 2.69515142907905952645E-15;
|
|
|
|
const m4pi = 1.273239544735162542821171882678754627704620361328125;
|
|
|
|
|
|
|
|
var x = x_;
|
|
|
|
if (math.isNan(x) or math.isInf(x)) {
|
|
|
|
return math.nan(f64);
|
|
|
|
}
|
|
|
|
|
|
|
|
var sign = false;
|
|
|
|
if (x < 0) {
|
|
|
|
x = -x;
|
|
|
|
}
|
|
|
|
|
|
|
|
var y = math.floor(x * m4pi);
|
2018-06-16 23:57:07 -07:00
|
|
|
var j = @floatToInt(i64, y);
|
2017-06-16 01:26:10 -07:00
|
|
|
|
|
|
|
if (j & 1 == 1) {
|
|
|
|
j += 1;
|
|
|
|
y += 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
j &= 7;
|
|
|
|
if (j > 3) {
|
|
|
|
j -= 4;
|
|
|
|
sign = !sign;
|
|
|
|
}
|
|
|
|
if (j > 1) {
|
|
|
|
sign = !sign;
|
|
|
|
}
|
|
|
|
|
|
|
|
const z = ((x - y * pi4a) - y * pi4b) - y * pi4c;
|
|
|
|
const w = z * z;
|
|
|
|
|
2017-12-21 21:50:30 -08:00
|
|
|
const r = r: {
|
2017-06-16 01:26:10 -07:00
|
|
|
if (j == 1 or j == 2) {
|
2017-12-21 21:50:30 -08:00
|
|
|
break :r z + z * w * (S5 + w * (S4 + w * (S3 + w * (S2 + w * (S1 + w * S0)))));
|
2017-06-16 01:26:10 -07:00
|
|
|
} else {
|
2017-12-21 21:50:30 -08:00
|
|
|
break :r 1.0 - 0.5 * w + w * w * (C5 + w * (C4 + w * (C3 + w * (C2 + w * (C1 + w * C0)))));
|
2017-06-16 01:26:10 -07:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
if (sign) {
|
2017-12-21 21:50:30 -08:00
|
|
|
return -r;
|
2017-06-16 01:26:10 -07:00
|
|
|
} else {
|
2017-12-21 21:50:30 -08:00
|
|
|
return r;
|
2017-06-16 01:26:10 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-19 11:36:33 -07:00
|
|
|
test "math.cos" {
|
2017-06-16 01:26:10 -07:00
|
|
|
assert(cos(f32(0.0)) == cos32(0.0));
|
|
|
|
assert(cos(f64(0.0)) == cos64(0.0));
|
|
|
|
}
|
|
|
|
|
2017-06-19 11:36:33 -07:00
|
|
|
test "math.cos32" {
|
2017-06-16 01:26:10 -07:00
|
|
|
const epsilon = 0.000001;
|
|
|
|
|
|
|
|
assert(math.approxEq(f32, cos32(0.0), 1.0, epsilon));
|
|
|
|
assert(math.approxEq(f32, cos32(0.2), 0.980067, epsilon));
|
|
|
|
assert(math.approxEq(f32, cos32(0.8923), 0.627623, epsilon));
|
|
|
|
assert(math.approxEq(f32, cos32(1.5), 0.070737, epsilon));
|
|
|
|
assert(math.approxEq(f32, cos32(37.45), 0.969132, epsilon));
|
|
|
|
assert(math.approxEq(f32, cos32(89.123), 0.400798, epsilon));
|
|
|
|
}
|
|
|
|
|
2017-06-19 11:36:33 -07:00
|
|
|
test "math.cos64" {
|
2017-06-16 01:26:10 -07:00
|
|
|
const epsilon = 0.000001;
|
|
|
|
|
|
|
|
assert(math.approxEq(f64, cos64(0.0), 1.0, epsilon));
|
|
|
|
assert(math.approxEq(f64, cos64(0.2), 0.980067, epsilon));
|
|
|
|
assert(math.approxEq(f64, cos64(0.8923), 0.627623, epsilon));
|
|
|
|
assert(math.approxEq(f64, cos64(1.5), 0.070737, epsilon));
|
|
|
|
assert(math.approxEq(f64, cos64(37.45), 0.969132, epsilon));
|
|
|
|
assert(math.approxEq(f64, cos64(89.123), 0.40080, epsilon));
|
|
|
|
}
|
2017-06-20 04:01:04 -07:00
|
|
|
|
|
|
|
test "math.cos32.special" {
|
|
|
|
assert(math.isNan(cos32(math.inf(f32))));
|
|
|
|
assert(math.isNan(cos32(-math.inf(f32))));
|
|
|
|
assert(math.isNan(cos32(math.nan(f32))));
|
|
|
|
}
|
|
|
|
|
|
|
|
test "math.cos64.special" {
|
|
|
|
assert(math.isNan(cos64(math.inf(f64))));
|
|
|
|
assert(math.isNan(cos64(-math.inf(f64))));
|
|
|
|
assert(math.isNan(cos64(math.nan(f64))));
|
|
|
|
}
|