| author | |
| committer | |
| log | f94964cd057ace39caa05c10d9626ac6a4beb23b |
| tree | 14d6ac67d878caccbb2ce5217de420f57f9c094a |
| parent | 7bbc8eb16c44d0aa9fee72fbe5607b44468a2872 |
This also starts the documentation effort for the math/ subdirectory.
The intent is to use this as a somewhat representative test-case for any
work on the documentation generator.5 files changed, 214 insertions(+), 352 deletions(-)
std/math/cos.zig+46-100| ... | @@ -1,18 +1,23 @@ | ... | @@ -1,18 +1,23 @@ |
| 1 | // Special Cases: | 1 | // Ported from go, which is licensed under a BSD-3 license. |
| 2 | // https://golang.org/LICENSE | ||
| 2 | // | 3 | // |
| 3 | // - cos(+-inf) = nan | 4 | // https://golang.org/src/math/sin.go |
| 4 | // - cos(nan) = nan | ||
| 5 | 5 | ||
| 6 | const builtin = @import("builtin"); | 6 | const builtin = @import("builtin"); |
| 7 | const std = @import("../std.zig"); | 7 | const std = @import("../std.zig"); |
| 8 | const math = std.math; | 8 | const math = std.math; |
| 9 | const expect = std.testing.expect; | 9 | const expect = std.testing.expect; |
| 10 | 10 | ||
| 11 | /// Returns the cosine of the radian value x. | ||
| 12 | /// | ||
| 13 | /// Special Cases: | ||
| 14 | /// - cos(+-inf) = nan | ||
| 15 | /// - cos(nan) = nan | ||
| 11 | pub fn cos(x: var) @typeOf(x) { | 16 | pub fn cos(x: var) @typeOf(x) { |
| 12 | const T = @typeOf(x); | 17 | const T = @typeOf(x); |
| 13 | return switch (T) { | 18 | return switch (T) { |
| 14 | f32 => cos32(x), | 19 | f32 => cos_(f32, x), |
| 15 | f64 => cos64(x), | 20 | f64 => cos_(f64, x), |
| 16 | else => @compileError("cos not implemented for " ++ @typeName(T)), | 21 | else => @compileError("cos not implemented for " ++ @typeName(T)), |
| 17 | }; | 22 | }; |
| 18 | } | 23 | } |
| ... | @@ -33,78 +38,24 @@ const C3 = 2.48015872888517045348E-5; | ... | @@ -33,78 +38,24 @@ const C3 = 2.48015872888517045348E-5; |
| 33 | const C4 = -1.38888888888730564116E-3; | 38 | const C4 = -1.38888888888730564116E-3; |
| 34 | const C5 = 4.16666666666665929218E-2; | 39 | const C5 = 4.16666666666665929218E-2; |
| 35 | 40 | ||
| 36 | // NOTE: This is taken from the go stdlib. The musl implementation is much more complex. | 41 | const pi4a = 7.85398125648498535156e-1; |
| 37 | // | 42 | const pi4b = 3.77489470793079817668E-8; |
| 38 | // This may have slight differences on some edge cases and may need to replaced if so. | 43 | const pi4c = 2.69515142907905952645E-15; |
| 39 | fn cos32(x_: f32) f32 { | 44 | const m4pi = 1.273239544735162542821171882678754627704620361328125; |
| 40 | const pi4a = 7.85398125648498535156e-1; | ||
| 41 | const pi4b = 3.77489470793079817668E-8; | ||
| 42 | const pi4c = 2.69515142907905952645E-15; | ||
| 43 | const m4pi = 1.273239544735162542821171882678754627704620361328125; | ||
| 44 | |||
| 45 | var x = x_; | ||
| 46 | if (math.isNan(x) or math.isInf(x)) { | ||
| 47 | return math.nan(f32); | ||
| 48 | } | ||
| 49 | 45 | ||
| 50 | var sign = false; | 46 | fn cos_(comptime T: type, x_: T) T { |
| 51 | if (x < 0) { | 47 | const I = @IntType(true, T.bit_count); |
| 52 | x = -x; | ||
| 53 | } | ||
| 54 | |||
| 55 | var y = math.floor(x * m4pi); | ||
| 56 | var j = @floatToInt(i64, y); | ||
| 57 | |||
| 58 | if (j & 1 == 1) { | ||
| 59 | j += 1; | ||
| 60 | y += 1; | ||
| 61 | } | ||
| 62 | |||
| 63 | j &= 7; | ||
| 64 | if (j > 3) { | ||
| 65 | j -= 4; | ||
| 66 | sign = !sign; | ||
| 67 | } | ||
| 68 | if (j > 1) { | ||
| 69 | sign = !sign; | ||
| 70 | } | ||
| 71 | |||
| 72 | const z = ((x - y * pi4a) - y * pi4b) - y * pi4c; | ||
| 73 | const w = z * z; | ||
| 74 | |||
| 75 | const r = r: { | ||
| 76 | if (j == 1 or j == 2) { | ||
| 77 | break :r z + z * w * (S5 + w * (S4 + w * (S3 + w * (S2 + w * (S1 + w * S0))))); | ||
| 78 | } else { | ||
| 79 | break :r 1.0 - 0.5 * w + w * w * (C5 + w * (C4 + w * (C3 + w * (C2 + w * (C1 + w * C0))))); | ||
| 80 | } | ||
| 81 | }; | ||
| 82 | |||
| 83 | if (sign) { | ||
| 84 | return -r; | ||
| 85 | } else { | ||
| 86 | return r; | ||
| 87 | } | ||
| 88 | } | ||
| 89 | |||
| 90 | fn cos64(x_: f64) f64 { | ||
| 91 | const pi4a = 7.85398125648498535156e-1; | ||
| 92 | const pi4b = 3.77489470793079817668E-8; | ||
| 93 | const pi4c = 2.69515142907905952645E-15; | ||
| 94 | const m4pi = 1.273239544735162542821171882678754627704620361328125; | ||
| 95 | 48 | ||
| 96 | var x = x_; | 49 | var x = x_; |
| 97 | if (math.isNan(x) or math.isInf(x)) { | 50 | if (math.isNan(x) or math.isInf(x)) { |
| 98 | return math.nan(f64); | 51 | return math.nan(f32); |
| 99 | } | 52 | } |
| 100 | 53 | ||
| 101 | var sign = false; | 54 | var sign = false; |
| 102 | if (x < 0) { | 55 | x = math.fabs(x); |
| 103 | x = -x; | ||
| 104 | } | ||
| 105 | 56 | ||
| 106 | var y = math.floor(x * m4pi); | 57 | var y = math.floor(x * m4pi); |
| 107 | var j = @floatToInt(i64, y); | 58 | var j = @floatToInt(I, y); |
| 108 | 59 | ||
| 109 | if (j & 1 == 1) { | 60 | if (j & 1 == 1) { |
| 110 | j += 1; | 61 | j += 1; |
| ... | @@ -123,56 +74,51 @@ fn cos64(x_: f64) f64 { | ... | @@ -123,56 +74,51 @@ fn cos64(x_: f64) f64 { |
| 123 | const z = ((x - y * pi4a) - y * pi4b) - y * pi4c; | 74 | const z = ((x - y * pi4a) - y * pi4b) - y * pi4c; |
| 124 | const w = z * z; | 75 | const w = z * z; |
| 125 | 76 | ||
| 126 | const r = r: { | 77 | const r = if (j == 1 or j == 2) |
| 127 | if (j == 1 or j == 2) { | 78 | z + z * w * (S5 + w * (S4 + w * (S3 + w * (S2 + w * (S1 + w * S0))))) |
| 128 | break :r z + z * w * (S5 + w * (S4 + w * (S3 + w * (S2 + w * (S1 + w * S0))))); | 79 | else |
| 129 | } else { | 80 | 1.0 - 0.5 * w + w * w * (C5 + w * (C4 + w * (C3 + w * (C2 + w * (C1 + w * C0))))); |
| 130 | break :r 1.0 - 0.5 * w + w * w * (C5 + w * (C4 + w * (C3 + w * (C2 + w * (C1 + w * C0))))); | ||
| 131 | } | ||
| 132 | }; | ||
| 133 | 81 | ||
| 134 | if (sign) { | 82 | return if (sign) -r else r; |
| 135 | return -r; | ||
| 136 | } else { | ||
| 137 | return r; | ||
| 138 | } | ||
| 139 | } | 83 | } |
| 140 | 84 | ||
| 141 | test "math.cos" { | 85 | test "math.cos" { |
| 142 | expect(cos(f32(0.0)) == cos32(0.0)); | 86 | expect(cos(f32(0.0)) == cos_(f32, 0.0)); |
| 143 | expect(cos(f64(0.0)) == cos64(0.0)); | 87 | expect(cos(f64(0.0)) == cos_(f64, 0.0)); |
| 144 | } | 88 | } |
| 145 | 89 | ||
| 146 | test "math.cos32" { | 90 | test "math.cos32" { |
| 147 | const epsilon = 0.000001; | 91 | const epsilon = 0.000001; |
| 148 | 92 | ||
| 149 | expect(math.approxEq(f32, cos32(0.0), 1.0, epsilon)); | 93 | expect(math.approxEq(f32, cos_(f32, 0.0), 1.0, epsilon)); |
| 150 | expect(math.approxEq(f32, cos32(0.2), 0.980067, epsilon)); | 94 | expect(math.approxEq(f32, cos_(f32, 0.2), 0.980067, epsilon)); |
| 151 | expect(math.approxEq(f32, cos32(0.8923), 0.627623, epsilon)); | 95 | expect(math.approxEq(f32, cos_(f32, 0.8923), 0.627623, epsilon)); |
| 152 | expect(math.approxEq(f32, cos32(1.5), 0.070737, epsilon)); | 96 | expect(math.approxEq(f32, cos_(f32, 1.5), 0.070737, epsilon)); |
| 153 | expect(math.approxEq(f32, cos32(37.45), 0.969132, epsilon)); | 97 | expect(math.approxEq(f32, cos_(f32, -1.5), 0.070737, epsilon)); |
| 154 | expect(math.approxEq(f32, cos32(89.123), 0.400798, epsilon)); | 98 | expect(math.approxEq(f32, cos_(f32, 37.45), 0.969132, epsilon)); |
| 99 | expect(math.approxEq(f32, cos_(f32, 89.123), 0.400798, epsilon)); | ||
| 155 | } | 100 | } |
| 156 | 101 | ||
| 157 | test "math.cos64" { | 102 | test "math.cos64" { |
| 158 | const epsilon = 0.000001; | 103 | const epsilon = 0.000001; |
| 159 | 104 | ||
| 160 | expect(math.approxEq(f64, cos64(0.0), 1.0, epsilon)); | 105 | expect(math.approxEq(f64, cos_(f64, 0.0), 1.0, epsilon)); |
| 161 | expect(math.approxEq(f64, cos64(0.2), 0.980067, epsilon)); | 106 | expect(math.approxEq(f64, cos_(f64, 0.2), 0.980067, epsilon)); |
| 162 | expect(math.approxEq(f64, cos64(0.8923), 0.627623, epsilon)); | 107 | expect(math.approxEq(f64, cos_(f64, 0.8923), 0.627623, epsilon)); |
| 163 | expect(math.approxEq(f64, cos64(1.5), 0.070737, epsilon)); | 108 | expect(math.approxEq(f64, cos_(f64, 1.5), 0.070737, epsilon)); |
| 164 | expect(math.approxEq(f64, cos64(37.45), 0.969132, epsilon)); | 109 | expect(math.approxEq(f64, cos_(f64, -1.5), 0.070737, epsilon)); |
| 165 | expect(math.approxEq(f64, cos64(89.123), 0.40080, epsilon)); | 110 | expect(math.approxEq(f64, cos_(f64, 37.45), 0.969132, epsilon)); |
| 111 | expect(math.approxEq(f64, cos_(f64, 89.123), 0.40080, epsilon)); | ||
| 166 | } | 112 | } |
| 167 | 113 | ||
| 168 | test "math.cos32.special" { | 114 | test "math.cos32.special" { |
| 169 | expect(math.isNan(cos32(math.inf(f32)))); | 115 | expect(math.isNan(cos_(f32, math.inf(f32)))); |
| 170 | expect(math.isNan(cos32(-math.inf(f32)))); | 116 | expect(math.isNan(cos_(f32, -math.inf(f32)))); |
| 171 | expect(math.isNan(cos32(math.nan(f32)))); | 117 | expect(math.isNan(cos_(f32, math.nan(f32)))); |
| 172 | } | 118 | } |
| 173 | 119 | ||
| 174 | test "math.cos64.special" { | 120 | test "math.cos64.special" { |
| 175 | expect(math.isNan(cos64(math.inf(f64)))); | 121 | expect(math.isNan(cos_(f64, math.inf(f64)))); |
| 176 | expect(math.isNan(cos64(-math.inf(f64)))); | 122 | expect(math.isNan(cos_(f64, -math.inf(f64)))); |
| 177 | expect(math.isNan(cos64(math.nan(f64)))); | 123 | expect(math.isNan(cos_(f64, math.nan(f64)))); |
| 178 | } | 124 | } |
std/math/fma.zig+9-1| ... | @@ -1,7 +1,14 @@ | ... | @@ -1,7 +1,14 @@ |
| 1 | // Ported from musl, which is licensed under the MIT license: | ||
| 2 | // https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT | ||
| 3 | // | ||
| 4 | // https://git.musl-libc.org/cgit/musl/tree/src/math/fmaf.c | ||
| 5 | // https://git.musl-libc.org/cgit/musl/tree/src/math/fma.c | ||
| 6 | |||
| 1 | const std = @import("../std.zig"); | 7 | const std = @import("../std.zig"); |
| 2 | const math = std.math; | 8 | const math = std.math; |
| 3 | const expect = std.testing.expect; | 9 | const expect = std.testing.expect; |
| 4 | 10 | ||
| 11 | /// Returns x * y + z with a single rounding error. | ||
| 5 | pub fn fma(comptime T: type, x: T, y: T, z: T) T { | 12 | pub fn fma(comptime T: type, x: T, y: T, z: T) T { |
| 6 | return switch (T) { | 13 | return switch (T) { |
| 7 | f32 => fma32(x, y, z), | 14 | f32 => fma32(x, y, z), |
| ... | @@ -16,7 +23,7 @@ fn fma32(x: f32, y: f32, z: f32) f32 { | ... | @@ -16,7 +23,7 @@ fn fma32(x: f32, y: f32, z: f32) f32 { |
| 16 | const u = @bitCast(u64, xy_z); | 23 | const u = @bitCast(u64, xy_z); |
| 17 | const e = (u >> 52) & 0x7FF; | 24 | const e = (u >> 52) & 0x7FF; |
| 18 | 25 | ||
| 19 | if ((u & 0x1FFFFFFF) != 0x10000000 or e == 0x7FF or xy_z - xy == z) { | 26 | if ((u & 0x1FFFFFFF) != 0x10000000 or e == 0x7FF or (xy_z - xy == z and xy_z - z == xy)) { |
| 20 | return @floatCast(f32, xy_z); | 27 | return @floatCast(f32, xy_z); |
| 21 | } else { | 28 | } else { |
| 22 | // TODO: Handle inexact case with double-rounding | 29 | // TODO: Handle inexact case with double-rounding |
| ... | @@ -24,6 +31,7 @@ fn fma32(x: f32, y: f32, z: f32) f32 { | ... | @@ -24,6 +31,7 @@ fn fma32(x: f32, y: f32, z: f32) f32 { |
| 24 | } | 31 | } |
| 25 | } | 32 | } |
| 26 | 33 | ||
| 34 | // NOTE: Upstream fma.c has been rewritten completely to raise fp exceptions more accurately. | ||
| 27 | fn fma64(x: f64, y: f64, z: f64) f64 { | 35 | fn fma64(x: f64, y: f64, z: f64) f64 { |
| 28 | if (!math.isFinite(x) or !math.isFinite(y)) { | 36 | if (!math.isFinite(x) or !math.isFinite(y)) { |
| 29 | return x * y + z; | 37 | return x * y + z; |
std/math/pow.zig+57-39| ... | @@ -1,32 +1,36 @@ | ... | @@ -1,32 +1,36 @@ |
| 1 | // Special Cases: | 1 | // Ported from go, which is licensed under a BSD-3 license. |
| 2 | // https://golang.org/LICENSE | ||
| 2 | // | 3 | // |
| 3 | // pow(x, +-0) = 1 for any x | 4 | // https://golang.org/src/math/pow.go |
| 4 | // pow(1, y) = 1 for any y | ||
| 5 | // pow(x, 1) = x for any x | ||
| 6 | // pow(nan, y) = nan | ||
| 7 | // pow(x, nan) = nan | ||
| 8 | // pow(+-0, y) = +-inf for y an odd integer < 0 | ||
| 9 | // pow(+-0, -inf) = +inf | ||
| 10 | // pow(+-0, +inf) = +0 | ||
| 11 | // pow(+-0, y) = +inf for finite y < 0 and not an odd integer | ||
| 12 | // pow(+-0, y) = +-0 for y an odd integer > 0 | ||
| 13 | // pow(+-0, y) = +0 for finite y > 0 and not an odd integer | ||
| 14 | // pow(-1, +-inf) = 1 | ||
| 15 | // pow(x, +inf) = +inf for |x| > 1 | ||
| 16 | // pow(x, -inf) = +0 for |x| > 1 | ||
| 17 | // pow(x, +inf) = +0 for |x| < 1 | ||
| 18 | // pow(x, -inf) = +inf for |x| < 1 | ||
| 19 | // pow(+inf, y) = +inf for y > 0 | ||
| 20 | // pow(+inf, y) = +0 for y < 0 | ||
| 21 | // pow(-inf, y) = pow(-0, -y) | ||
| 22 | // pow(x, y) = nan for finite x < 0 and finite non-integer y | ||
| 23 | 5 | ||
| 24 | const builtin = @import("builtin"); | 6 | const builtin = @import("builtin"); |
| 25 | const std = @import("../std.zig"); | 7 | const std = @import("../std.zig"); |
| 26 | const math = std.math; | 8 | const math = std.math; |
| 27 | const expect = std.testing.expect; | 9 | const expect = std.testing.expect; |
| 28 | 10 | ||
| 29 | // This implementation is taken from the go stlib, musl is a bit more complex. | 11 | /// Returns x raised to the power of y (x^y). |
| 12 | /// | ||
| 13 | /// Special Cases: | ||
| 14 | /// - pow(x, +-0) = 1 for any x | ||
| 15 | /// - pow(1, y) = 1 for any y | ||
| 16 | /// - pow(x, 1) = x for any x | ||
| 17 | /// - pow(nan, y) = nan | ||
| 18 | /// - pow(x, nan) = nan | ||
| 19 | /// - pow(+-0, y) = +-inf for y an odd integer < 0 | ||
| 20 | /// - pow(+-0, -inf) = +inf | ||
| 21 | /// - pow(+-0, +inf) = +0 | ||
| 22 | /// - pow(+-0, y) = +inf for finite y < 0 and not an odd integer | ||
| 23 | /// - pow(+-0, y) = +-0 for y an odd integer > 0 | ||
| 24 | /// - pow(+-0, y) = +0 for finite y > 0 and not an odd integer | ||
| 25 | /// - pow(-1, +-inf) = 1 | ||
| 26 | /// - pow(x, +inf) = +inf for |x| > 1 | ||
| 27 | /// - pow(x, -inf) = +0 for |x| > 1 | ||
| 28 | /// - pow(x, +inf) = +0 for |x| < 1 | ||
| 29 | /// - pow(x, -inf) = +inf for |x| < 1 | ||
| 30 | /// - pow(+inf, y) = +inf for y > 0 | ||
| 31 | /// - pow(+inf, y) = +0 for y < 0 | ||
| 32 | /// - pow(-inf, y) = pow(-0, -y) | ||
| 33 | /// - pow(x, y) = nan for finite x < 0 and finite non-integer y | ||
| 30 | pub fn pow(comptime T: type, x: T, y: T) T { | 34 | pub fn pow(comptime T: type, x: T, y: T) T { |
| 31 | if (@typeInfo(T) == builtin.TypeId.Int) { | 35 | if (@typeInfo(T) == builtin.TypeId.Int) { |
| 32 | return math.powi(T, x, y) catch unreachable; | 36 | return math.powi(T, x, y) catch unreachable; |
| ... | @@ -53,15 +57,6 @@ pub fn pow(comptime T: type, x: T, y: T) T { | ... | @@ -53,15 +57,6 @@ pub fn pow(comptime T: type, x: T, y: T) T { |
| 53 | return x; | 57 | return x; |
| 54 | } | 58 | } |
| 55 | 59 | ||
| 56 | // special case sqrt | ||
| 57 | if (y == 0.5) { | ||
| 58 | return math.sqrt(x); | ||
| 59 | } | ||
| 60 | |||
| 61 | if (y == -0.5) { | ||
| 62 | return 1 / math.sqrt(x); | ||
| 63 | } | ||
| 64 | |||
| 65 | if (x == 0) { | 60 | if (x == 0) { |
| 66 | if (y < 0) { | 61 | if (y < 0) { |
| 67 | // pow(+-0, y) = +- 0 for y an odd integer | 62 | // pow(+-0, y) = +- 0 for y an odd integer |
| ... | @@ -112,14 +107,16 @@ pub fn pow(comptime T: type, x: T, y: T) T { | ... | @@ -112,14 +107,16 @@ pub fn pow(comptime T: type, x: T, y: T) T { |
| 112 | } | 107 | } |
| 113 | } | 108 | } |
| 114 | 109 | ||
| 115 | var ay = y; | 110 | // special case sqrt |
| 116 | var flip = false; | 111 | if (y == 0.5) { |
| 117 | if (ay < 0) { | 112 | return math.sqrt(x); |
| 118 | ay = -ay; | 113 | } |
| 119 | flip = true; | 114 | |
| 115 | if (y == -0.5) { | ||
| 116 | return 1 / math.sqrt(x); | ||
| 120 | } | 117 | } |
| 121 | 118 | ||
| 122 | const r1 = math.modf(ay); | 119 | const r1 = math.modf(math.fabs(y)); |
| 123 | var yi = r1.ipart; | 120 | var yi = r1.ipart; |
| 124 | var yf = r1.fpart; | 121 | var yf = r1.fpart; |
| 125 | 122 | ||
| ... | @@ -148,8 +145,18 @@ pub fn pow(comptime T: type, x: T, y: T) T { | ... | @@ -148,8 +145,18 @@ pub fn pow(comptime T: type, x: T, y: T) T { |
| 148 | var xe = r2.exponent; | 145 | var xe = r2.exponent; |
| 149 | var x1 = r2.significand; | 146 | var x1 = r2.significand; |
| 150 | 147 | ||
| 151 | var i = @floatToInt(i32, yi); | 148 | var i = @floatToInt(@IntType(true, T.bit_count), yi); |
| 152 | while (i != 0) : (i >>= 1) { | 149 | while (i != 0) : (i >>= 1) { |
| 150 | const overflow_shift = math.floatExponentBits(T) + 1; | ||
| 151 | if (xe < -(1 << overflow_shift) or (1 << overflow_shift) < xe) { | ||
| 152 | // catch xe before it overflows the left shift below | ||
| 153 | // Since i != 0 it has at least one bit still set, so ae will accumulate xe | ||
| 154 | // on at least one more iteration, ae += xe is a lower bound on ae | ||
| 155 | // the lower bound on ae exceeds the size of a float exp | ||
| 156 | // so the final call to Ldexp will produce under/overflow (0/Inf) | ||
| 157 | ae += xe; | ||
| 158 | break; | ||
| 159 | } | ||
| 153 | if (i & 1 == 1) { | 160 | if (i & 1 == 1) { |
| 154 | a1 *= x1; | 161 | a1 *= x1; |
| 155 | ae += xe; | 162 | ae += xe; |
| ... | @@ -163,7 +170,7 @@ pub fn pow(comptime T: type, x: T, y: T) T { | ... | @@ -163,7 +170,7 @@ pub fn pow(comptime T: type, x: T, y: T) T { |
| 163 | } | 170 | } |
| 164 | 171 | ||
| 165 | // a *= a1 * 2^ae | 172 | // a *= a1 * 2^ae |
| 166 | if (flip) { | 173 | if (y < 0) { |
| 167 | a1 = 1 / a1; | 174 | a1 = 1 / a1; |
| 168 | ae = -ae; | 175 | ae = -ae; |
| 169 | } | 176 | } |
| ... | @@ -202,6 +209,9 @@ test "math.pow.special" { | ... | @@ -202,6 +209,9 @@ test "math.pow.special" { |
| 202 | expect(pow(f32, 45, 1.0) == 45); | 209 | expect(pow(f32, 45, 1.0) == 45); |
| 203 | expect(pow(f32, -45, 1.0) == -45); | 210 | expect(pow(f32, -45, 1.0) == -45); |
| 204 | expect(math.isNan(pow(f32, math.nan(f32), 5.0))); | 211 | expect(math.isNan(pow(f32, math.nan(f32), 5.0))); |
| 212 | expect(math.isPositiveInf(pow(f32, -math.inf(f32), 0.5))); | ||
| 213 | expect(math.isPositiveInf(pow(f32, -0, -0.5))); | ||
| 214 | expect(pow(f32, -0, 0.5) == 0); | ||
| 205 | expect(math.isNan(pow(f32, 5.0, math.nan(f32)))); | 215 | expect(math.isNan(pow(f32, 5.0, math.nan(f32)))); |
| 206 | expect(math.isPositiveInf(pow(f32, 0.0, -1.0))); | 216 | expect(math.isPositiveInf(pow(f32, 0.0, -1.0))); |
| 207 | //expect(math.isNegativeInf(pow(f32, -0.0, -3.0))); TODO is this required? | 217 | //expect(math.isNegativeInf(pow(f32, -0.0, -3.0))); TODO is this required? |
| ... | @@ -232,3 +242,11 @@ test "math.pow.special" { | ... | @@ -232,3 +242,11 @@ test "math.pow.special" { |
| 232 | expect(math.isNan(pow(f32, -1.0, 1.2))); | 242 | expect(math.isNan(pow(f32, -1.0, 1.2))); |
| 233 | expect(math.isNan(pow(f32, -12.4, 78.5))); | 243 | expect(math.isNan(pow(f32, -12.4, 78.5))); |
| 234 | } | 244 | } |
| 245 | |||
| 246 | test "math.pow.overflow" { | ||
| 247 | expect(math.isPositiveInf(pow(f64, 2, 1 << 32))); | ||
| 248 | expect(pow(f64, 2, -(1 << 32)) == 0); | ||
| 249 | expect(math.isNegativeInf(pow(f64, -2, (1 << 32) + 1))); | ||
| 250 | expect(pow(f64, 0.5, 1 << 45) == 0); | ||
| 251 | expect(math.isPositiveInf(pow(f64, 0.5, -(1 << 45)))); | ||
| 252 | } |
std/math/sin.zig+52-108| ... | @@ -1,19 +1,24 @@ | ... | @@ -1,19 +1,24 @@ |
| 1 | // Special Cases: | 1 | // Ported from go, which is licensed under a BSD-3 license. |
| 2 | // https://golang.org/LICENSE | ||
| 2 | // | 3 | // |
| 3 | // - sin(+-0) = +-0 | 4 | // https://golang.org/src/math/sin.go |
| 4 | // - sin(+-inf) = nan | ||
| 5 | // - sin(nan) = nan | ||
| 6 | 5 | ||
| 7 | const builtin = @import("builtin"); | 6 | const builtin = @import("builtin"); |
| 8 | const std = @import("../std.zig"); | 7 | const std = @import("../std.zig"); |
| 9 | const math = std.math; | 8 | const math = std.math; |
| 10 | const expect = std.testing.expect; | 9 | const expect = std.testing.expect; |
| 11 | 10 | ||
| 11 | /// Returns the sine of the radian value x. | ||
| 12 | /// | ||
| 13 | /// Special Cases: | ||
| 14 | /// - sin(+-0) = +-0 | ||
| 15 | /// - sin(+-inf) = nan | ||
| 16 | /// - sin(nan) = nan | ||
| 12 | pub fn sin(x: var) @typeOf(x) { | 17 | pub fn sin(x: var) @typeOf(x) { |
| 13 | const T = @typeOf(x); | 18 | const T = @typeOf(x); |
| 14 | return switch (T) { | 19 | return switch (T) { |
| 15 | f32 => sin32(x), | 20 | f32 => sin_(T, x), |
| 16 | f64 => sin64(x), | 21 | f64 => sin_(T, x), |
| 17 | else => @compileError("sin not implemented for " ++ @typeName(T)), | 22 | else => @compileError("sin not implemented for " ++ @typeName(T)), |
| 18 | }; | 23 | }; |
| 19 | } | 24 | } |
| ... | @@ -34,83 +39,27 @@ const C3 = 2.48015872888517045348E-5; | ... | @@ -34,83 +39,27 @@ const C3 = 2.48015872888517045348E-5; |
| 34 | const C4 = -1.38888888888730564116E-3; | 39 | const C4 = -1.38888888888730564116E-3; |
| 35 | const C5 = 4.16666666666665929218E-2; | 40 | const C5 = 4.16666666666665929218E-2; |
| 36 | 41 | ||
| 37 | // NOTE: This is taken from the go stdlib. The musl implementation is much more complex. | 42 | const pi4a = 7.85398125648498535156e-1; |
| 38 | // | 43 | const pi4b = 3.77489470793079817668E-8; |
| 39 | // This may have slight differences on some edge cases and may need to replaced if so. | 44 | const pi4c = 2.69515142907905952645E-15; |
| 40 | fn sin32(x_: f32) f32 { | 45 | const m4pi = 1.273239544735162542821171882678754627704620361328125; |
| 41 | const pi4a = 7.85398125648498535156e-1; | ||
| 42 | const pi4b = 3.77489470793079817668E-8; | ||
| 43 | const pi4c = 2.69515142907905952645E-15; | ||
| 44 | const m4pi = 1.273239544735162542821171882678754627704620361328125; | ||
| 45 | |||
| 46 | var x = x_; | ||
| 47 | if (x == 0 or math.isNan(x)) { | ||
| 48 | return x; | ||
| 49 | } | ||
| 50 | if (math.isInf(x)) { | ||
| 51 | return math.nan(f32); | ||
| 52 | } | ||
| 53 | |||
| 54 | var sign = false; | ||
| 55 | if (x < 0) { | ||
| 56 | x = -x; | ||
| 57 | sign = true; | ||
| 58 | } | ||
| 59 | |||
| 60 | var y = math.floor(x * m4pi); | ||
| 61 | var j = @floatToInt(i64, y); | ||
| 62 | |||
| 63 | if (j & 1 == 1) { | ||
| 64 | j += 1; | ||
| 65 | y += 1; | ||
| 66 | } | ||
| 67 | 46 | ||
| 68 | j &= 7; | 47 | fn sin_(comptime T: type, x_: T) T { |
| 69 | if (j > 3) { | 48 | const I = @IntType(true, T.bit_count); |
| 70 | j -= 4; | ||
| 71 | sign = !sign; | ||
| 72 | } | ||
| 73 | |||
| 74 | const z = ((x - y * pi4a) - y * pi4b) - y * pi4c; | ||
| 75 | const w = z * z; | ||
| 76 | |||
| 77 | const r = r: { | ||
| 78 | if (j == 1 or j == 2) { | ||
| 79 | break :r 1.0 - 0.5 * w + w * w * (C5 + w * (C4 + w * (C3 + w * (C2 + w * (C1 + w * C0))))); | ||
| 80 | } else { | ||
| 81 | break :r z + z * w * (S5 + w * (S4 + w * (S3 + w * (S2 + w * (S1 + w * S0))))); | ||
| 82 | } | ||
| 83 | }; | ||
| 84 | |||
| 85 | if (sign) { | ||
| 86 | return -r; | ||
| 87 | } else { | ||
| 88 | return r; | ||
| 89 | } | ||
| 90 | } | ||
| 91 | |||
| 92 | fn sin64(x_: f64) f64 { | ||
| 93 | const pi4a = 7.85398125648498535156e-1; | ||
| 94 | const pi4b = 3.77489470793079817668E-8; | ||
| 95 | const pi4c = 2.69515142907905952645E-15; | ||
| 96 | const m4pi = 1.273239544735162542821171882678754627704620361328125; | ||
| 97 | 49 | ||
| 98 | var x = x_; | 50 | var x = x_; |
| 99 | if (x == 0 or math.isNan(x)) { | 51 | if (x == 0 or math.isNan(x)) { |
| 100 | return x; | 52 | return x; |
| 101 | } | 53 | } |
| 102 | if (math.isInf(x)) { | 54 | if (math.isInf(x)) { |
| 103 | return math.nan(f64); | 55 | return math.nan(T); |
| 104 | } | 56 | } |
| 105 | 57 | ||
| 106 | var sign = false; | 58 | var sign = x < 0; |
| 107 | if (x < 0) { | 59 | x = math.fabs(x); |
| 108 | x = -x; | ||
| 109 | sign = true; | ||
| 110 | } | ||
| 111 | 60 | ||
| 112 | var y = math.floor(x * m4pi); | 61 | var y = math.floor(x * m4pi); |
| 113 | var j = @floatToInt(i64, y); | 62 | var j = @floatToInt(I, y); |
| 114 | 63 | ||
| 115 | if (j & 1 == 1) { | 64 | if (j & 1 == 1) { |
| 116 | j += 1; | 65 | j += 1; |
| ... | @@ -126,61 +75,56 @@ fn sin64(x_: f64) f64 { | ... | @@ -126,61 +75,56 @@ fn sin64(x_: f64) f64 { |
| 126 | const z = ((x - y * pi4a) - y * pi4b) - y * pi4c; | 75 | const z = ((x - y * pi4a) - y * pi4b) - y * pi4c; |
| 127 | const w = z * z; | 76 | const w = z * z; |
| 128 | 77 | ||
| 129 | const r = r: { | 78 | const r = if (j == 1 or j == 2) |
| 130 | if (j == 1 or j == 2) { | 79 | 1.0 - 0.5 * w + w * w * (C5 + w * (C4 + w * (C3 + w * (C2 + w * (C1 + w * C0))))) |
| 131 | break :r 1.0 - 0.5 * w + w * w * (C5 + w * (C4 + w * (C3 + w * (C2 + w * (C1 + w * C0))))); | 80 | else |
| 132 | } else { | 81 | z + z * w * (S5 + w * (S4 + w * (S3 + w * (S2 + w * (S1 + w * S0))))); |
| 133 | break :r z + z * w * (S5 + w * (S4 + w * (S3 + w * (S2 + w * (S1 + w * S0))))); | ||
| 134 | } | ||
| 135 | }; | ||
| 136 | 82 | ||
| 137 | if (sign) { | 83 | return if (sign) -r else r; |
| 138 | return -r; | ||
| 139 | } else { | ||
| 140 | return r; | ||
| 141 | } | ||
| 142 | } | 84 | } |
| 143 | 85 | ||
| 144 | test "math.sin" { | 86 | test "math.sin" { |
| 145 | expect(sin(f32(0.0)) == sin32(0.0)); | 87 | expect(sin(f32(0.0)) == sin_(f32, 0.0)); |
| 146 | expect(sin(f64(0.0)) == sin64(0.0)); | 88 | expect(sin(f64(0.0)) == sin_(f64, 0.0)); |
| 147 | expect(comptime (math.sin(f64(2))) == math.sin(f64(2))); | 89 | expect(comptime (math.sin(f64(2))) == math.sin(f64(2))); |
| 148 | } | 90 | } |
| 149 | 91 | ||
| 150 | test "math.sin32" { | 92 | test "math.sin32" { |
| 151 | const epsilon = 0.000001; | 93 | const epsilon = 0.000001; |
| 152 | 94 | ||
| 153 | expect(math.approxEq(f32, sin32(0.0), 0.0, epsilon)); | 95 | expect(math.approxEq(f32, sin_(f32, 0.0), 0.0, epsilon)); |
| 154 | expect(math.approxEq(f32, sin32(0.2), 0.198669, epsilon)); | 96 | expect(math.approxEq(f32, sin_(f32, 0.2), 0.198669, epsilon)); |
| 155 | expect(math.approxEq(f32, sin32(0.8923), 0.778517, epsilon)); | 97 | expect(math.approxEq(f32, sin_(f32, 0.8923), 0.778517, epsilon)); |
| 156 | expect(math.approxEq(f32, sin32(1.5), 0.997495, epsilon)); | 98 | expect(math.approxEq(f32, sin_(f32, 1.5), 0.997495, epsilon)); |
| 157 | expect(math.approxEq(f32, sin32(37.45), -0.246544, epsilon)); | 99 | expect(math.approxEq(f32, sin_(f32, -1.5), -0.997495, epsilon)); |
| 158 | expect(math.approxEq(f32, sin32(89.123), 0.916166, epsilon)); | 100 | expect(math.approxEq(f32, sin_(f32, 37.45), -0.246544, epsilon)); |
| 101 | expect(math.approxEq(f32, sin_(f32, 89.123), 0.916166, epsilon)); | ||
| 159 | } | 102 | } |
| 160 | 103 | ||
| 161 | test "math.sin64" { | 104 | test "math.sin64" { |
| 162 | const epsilon = 0.000001; | 105 | const epsilon = 0.000001; |
| 163 | 106 | ||
| 164 | expect(math.approxEq(f64, sin64(0.0), 0.0, epsilon)); | 107 | expect(math.approxEq(f64, sin_(f64, 0.0), 0.0, epsilon)); |
| 165 | expect(math.approxEq(f64, sin64(0.2), 0.198669, epsilon)); | 108 | expect(math.approxEq(f64, sin_(f64, 0.2), 0.198669, epsilon)); |
| 166 | expect(math.approxEq(f64, sin64(0.8923), 0.778517, epsilon)); | 109 | expect(math.approxEq(f64, sin_(f64, 0.8923), 0.778517, epsilon)); |
| 167 | expect(math.approxEq(f64, sin64(1.5), 0.997495, epsilon)); | 110 | expect(math.approxEq(f64, sin_(f64, 1.5), 0.997495, epsilon)); |
| 168 | expect(math.approxEq(f64, sin64(37.45), -0.246543, epsilon)); | 111 | expect(math.approxEq(f64, sin_(f64, -1.5), -0.997495, epsilon)); |
| 169 | expect(math.approxEq(f64, sin64(89.123), 0.916166, epsilon)); | 112 | expect(math.approxEq(f64, sin_(f64, 37.45), -0.246543, epsilon)); |
| 113 | expect(math.approxEq(f64, sin_(f64, 89.123), 0.916166, epsilon)); | ||
| 170 | } | 114 | } |
| 171 | 115 | ||
| 172 | test "math.sin32.special" { | 116 | test "math.sin32.special" { |
| 173 | expect(sin32(0.0) == 0.0); | 117 | expect(sin_(f32, 0.0) == 0.0); |
| 174 | expect(sin32(-0.0) == -0.0); | 118 | expect(sin_(f32, -0.0) == -0.0); |
| 175 | expect(math.isNan(sin32(math.inf(f32)))); | 119 | expect(math.isNan(sin_(f32, math.inf(f32)))); |
| 176 | expect(math.isNan(sin32(-math.inf(f32)))); | 120 | expect(math.isNan(sin_(f32, -math.inf(f32)))); |
| 177 | expect(math.isNan(sin32(math.nan(f32)))); | 121 | expect(math.isNan(sin_(f32, math.nan(f32)))); |
| 178 | } | 122 | } |
| 179 | 123 | ||
| 180 | test "math.sin64.special" { | 124 | test "math.sin64.special" { |
| 181 | expect(sin64(0.0) == 0.0); | 125 | expect(sin_(f64, 0.0) == 0.0); |
| 182 | expect(sin64(-0.0) == -0.0); | 126 | expect(sin_(f64, -0.0) == -0.0); |
| 183 | expect(math.isNan(sin64(math.inf(f64)))); | 127 | expect(math.isNan(sin_(f64, math.inf(f64)))); |
| 184 | expect(math.isNan(sin64(-math.inf(f64)))); | 128 | expect(math.isNan(sin_(f64, -math.inf(f64)))); |
| 185 | expect(math.isNan(sin64(math.nan(f64)))); | 129 | expect(math.isNan(sin_(f64, math.nan(f64)))); |
| 186 | } | 130 | } |
std/math/tan.zig+50-104| ... | @@ -1,19 +1,24 @@ | ... | @@ -1,19 +1,24 @@ |
| 1 | // Special Cases: | 1 | // Ported from go, which is licensed under a BSD-3 license. |
| 2 | // https://golang.org/LICENSE | ||
| 2 | // | 3 | // |
| 3 | // - tan(+-0) = +-0 | 4 | // https://golang.org/src/math/tan.go |
| 4 | // - tan(+-inf) = nan | ||
| 5 | // - tan(nan) = nan | ||
| 6 | 5 | ||
| 7 | const builtin = @import("builtin"); | 6 | const builtin = @import("builtin"); |
| 8 | const std = @import("../std.zig"); | 7 | const std = @import("../std.zig"); |
| 9 | const math = std.math; | 8 | const math = std.math; |
| 10 | const expect = std.testing.expect; | 9 | const expect = std.testing.expect; |
| 11 | 10 | ||
| 11 | /// Returns the tangent of the radian value x. | ||
| 12 | /// | ||
| 13 | /// Special Cases: | ||
| 14 | /// - tan(+-0) = +-0 | ||
| 15 | /// - tan(+-inf) = nan | ||
| 16 | /// - tan(nan) = nan | ||
| 12 | pub fn tan(x: var) @typeOf(x) { | 17 | pub fn tan(x: var) @typeOf(x) { |
| 13 | const T = @typeOf(x); | 18 | const T = @typeOf(x); |
| 14 | return switch (T) { | 19 | return switch (T) { |
| 15 | f32 => tan32(x), | 20 | f32 => tan_(f32, x), |
| 16 | f64 => tan64(x), | 21 | f64 => tan_(f64, x), |
| 17 | else => @compileError("tan not implemented for " ++ @typeName(T)), | 22 | else => @compileError("tan not implemented for " ++ @typeName(T)), |
| 18 | }; | 23 | }; |
| 19 | } | 24 | } |
| ... | @@ -27,80 +32,27 @@ const Tq2 = -1.32089234440210967447E6; | ... | @@ -27,80 +32,27 @@ const Tq2 = -1.32089234440210967447E6; |
| 27 | const Tq3 = 2.50083801823357915839E7; | 32 | const Tq3 = 2.50083801823357915839E7; |
| 28 | const Tq4 = -5.38695755929454629881E7; | 33 | const Tq4 = -5.38695755929454629881E7; |
| 29 | 34 | ||
| 30 | // NOTE: This is taken from the go stdlib. The musl implementation is much more complex. | 35 | const pi4a = 7.85398125648498535156e-1; |
| 31 | // | 36 | const pi4b = 3.77489470793079817668E-8; |
| 32 | // This may have slight differences on some edge cases and may need to replaced if so. | 37 | const pi4c = 2.69515142907905952645E-15; |
| 33 | fn tan32(x_: f32) f32 { | 38 | const m4pi = 1.273239544735162542821171882678754627704620361328125; |
| 34 | const pi4a = 7.85398125648498535156e-1; | ||
| 35 | const pi4b = 3.77489470793079817668E-8; | ||
| 36 | const pi4c = 2.69515142907905952645E-15; | ||
| 37 | const m4pi = 1.273239544735162542821171882678754627704620361328125; | ||
| 38 | |||
| 39 | var x = x_; | ||
| 40 | if (x == 0 or math.isNan(x)) { | ||
| 41 | return x; | ||
| 42 | } | ||
| 43 | if (math.isInf(x)) { | ||
| 44 | return math.nan(f32); | ||
| 45 | } | ||
| 46 | |||
| 47 | var sign = false; | ||
| 48 | if (x < 0) { | ||
| 49 | x = -x; | ||
| 50 | sign = true; | ||
| 51 | } | ||
| 52 | |||
| 53 | var y = math.floor(x * m4pi); | ||
| 54 | var j = @floatToInt(i64, y); | ||
| 55 | |||
| 56 | if (j & 1 == 1) { | ||
| 57 | j += 1; | ||
| 58 | y += 1; | ||
| 59 | } | ||
| 60 | |||
| 61 | const z = ((x - y * pi4a) - y * pi4b) - y * pi4c; | ||
| 62 | const w = z * z; | ||
| 63 | |||
| 64 | var r = r: { | ||
| 65 | if (w > 1e-14) { | ||
| 66 | break :r z + z * (w * ((Tp0 * w + Tp1) * w + Tp2) / ((((w + Tq1) * w + Tq2) * w + Tq3) * w + Tq4)); | ||
| 67 | } else { | ||
| 68 | break :r z; | ||
| 69 | } | ||
| 70 | }; | ||
| 71 | |||
| 72 | if (j & 2 == 2) { | ||
| 73 | r = -1 / r; | ||
| 74 | } | ||
| 75 | if (sign) { | ||
| 76 | r = -r; | ||
| 77 | } | ||
| 78 | |||
| 79 | return r; | ||
| 80 | } | ||
| 81 | 39 | ||
| 82 | fn tan64(x_: f64) f64 { | 40 | fn tan_(comptime T: type, x_: T) T { |
| 83 | const pi4a = 7.85398125648498535156e-1; | 41 | const I = @IntType(true, T.bit_count); |
| 84 | const pi4b = 3.77489470793079817668E-8; | ||
| 85 | const pi4c = 2.69515142907905952645E-15; | ||
| 86 | const m4pi = 1.273239544735162542821171882678754627704620361328125; | ||
| 87 | 42 | ||
| 88 | var x = x_; | 43 | var x = x_; |
| 89 | if (x == 0 or math.isNan(x)) { | 44 | if (x == 0 or math.isNan(x)) { |
| 90 | return x; | 45 | return x; |
| 91 | } | 46 | } |
| 92 | if (math.isInf(x)) { | 47 | if (math.isInf(x)) { |
| 93 | return math.nan(f64); | 48 | return math.nan(T); |
| 94 | } | 49 | } |
| 95 | 50 | ||
| 96 | var sign = false; | 51 | var sign = x < 0; |
| 97 | if (x < 0) { | 52 | x = math.fabs(x); |
| 98 | x = -x; | ||
| 99 | sign = true; | ||
| 100 | } | ||
| 101 | 53 | ||
| 102 | var y = math.floor(x * m4pi); | 54 | var y = math.floor(x * m4pi); |
| 103 | var j = @floatToInt(i64, y); | 55 | var j = @floatToInt(I, y); |
| 104 | 56 | ||
| 105 | if (j & 1 == 1) { | 57 | if (j & 1 == 1) { |
| 106 | j += 1; | 58 | j += 1; |
| ... | @@ -110,63 +62,57 @@ fn tan64(x_: f64) f64 { | ... | @@ -110,63 +62,57 @@ fn tan64(x_: f64) f64 { |
| 110 | const z = ((x - y * pi4a) - y * pi4b) - y * pi4c; | 62 | const z = ((x - y * pi4a) - y * pi4b) - y * pi4c; |
| 111 | const w = z * z; | 63 | const w = z * z; |
| 112 | 64 | ||
| 113 | var r = r: { | 65 | var r = if (w > 1e-14) |
| 114 | if (w > 1e-14) { | 66 | z + z * (w * ((Tp0 * w + Tp1) * w + Tp2) / ((((w + Tq1) * w + Tq2) * w + Tq3) * w + Tq4)) |
| 115 | break :r z + z * (w * ((Tp0 * w + Tp1) * w + Tp2) / ((((w + Tq1) * w + Tq2) * w + Tq3) * w + Tq4)); | 67 | else |
| 116 | } else { | 68 | z; |
| 117 | break :r z; | ||
| 118 | } | ||
| 119 | }; | ||
| 120 | 69 | ||
| 121 | if (j & 2 == 2) { | 70 | if (j & 2 == 2) { |
| 122 | r = -1 / r; | 71 | r = -1 / r; |
| 123 | } | 72 | } |
| 124 | if (sign) { | ||
| 125 | r = -r; | ||
| 126 | } | ||
| 127 | 73 | ||
| 128 | return r; | 74 | return if (sign) -r else r; |
| 129 | } | 75 | } |
| 130 | 76 | ||
| 131 | test "math.tan" { | 77 | test "math.tan" { |
| 132 | expect(tan(f32(0.0)) == tan32(0.0)); | 78 | expect(tan(f32(0.0)) == tan_(f32, 0.0)); |
| 133 | expect(tan(f64(0.0)) == tan64(0.0)); | 79 | expect(tan(f64(0.0)) == tan_(f64, 0.0)); |
| 134 | } | 80 | } |
| 135 | 81 | ||
| 136 | test "math.tan32" { | 82 | test "math.tan32" { |
| 137 | const epsilon = 0.000001; | 83 | const epsilon = 0.000001; |
| 138 | 84 | ||
| 139 | expect(math.approxEq(f32, tan32(0.0), 0.0, epsilon)); | 85 | expect(math.approxEq(f32, tan_(f32, 0.0), 0.0, epsilon)); |
| 140 | expect(math.approxEq(f32, tan32(0.2), 0.202710, epsilon)); | 86 | expect(math.approxEq(f32, tan_(f32, 0.2), 0.202710, epsilon)); |
| 141 | expect(math.approxEq(f32, tan32(0.8923), 1.240422, epsilon)); | 87 | expect(math.approxEq(f32, tan_(f32, 0.8923), 1.240422, epsilon)); |
| 142 | expect(math.approxEq(f32, tan32(1.5), 14.101420, epsilon)); | 88 | expect(math.approxEq(f32, tan_(f32, 1.5), 14.101420, epsilon)); |
| 143 | expect(math.approxEq(f32, tan32(37.45), -0.254397, epsilon)); | 89 | expect(math.approxEq(f32, tan_(f32, 37.45), -0.254397, epsilon)); |
| 144 | expect(math.approxEq(f32, tan32(89.123), 2.285852, epsilon)); | 90 | expect(math.approxEq(f32, tan_(f32, 89.123), 2.285852, epsilon)); |
| 145 | } | 91 | } |
| 146 | 92 | ||
| 147 | test "math.tan64" { | 93 | test "math.tan64" { |
| 148 | const epsilon = 0.000001; | 94 | const epsilon = 0.000001; |
| 149 | 95 | ||
| 150 | expect(math.approxEq(f64, tan64(0.0), 0.0, epsilon)); | 96 | expect(math.approxEq(f64, tan_(f64, 0.0), 0.0, epsilon)); |
| 151 | expect(math.approxEq(f64, tan64(0.2), 0.202710, epsilon)); | 97 | expect(math.approxEq(f64, tan_(f64, 0.2), 0.202710, epsilon)); |
| 152 | expect(math.approxEq(f64, tan64(0.8923), 1.240422, epsilon)); | 98 | expect(math.approxEq(f64, tan_(f64, 0.8923), 1.240422, epsilon)); |
| 153 | expect(math.approxEq(f64, tan64(1.5), 14.101420, epsilon)); | 99 | expect(math.approxEq(f64, tan_(f64, 1.5), 14.101420, epsilon)); |
| 154 | expect(math.approxEq(f64, tan64(37.45), -0.254397, epsilon)); | 100 | expect(math.approxEq(f64, tan_(f64, 37.45), -0.254397, epsilon)); |
| 155 | expect(math.approxEq(f64, tan64(89.123), 2.2858376, epsilon)); | 101 | expect(math.approxEq(f64, tan_(f64, 89.123), 2.2858376, epsilon)); |
| 156 | } | 102 | } |
| 157 | 103 | ||
| 158 | test "math.tan32.special" { | 104 | test "math.tan32.special" { |
| 159 | expect(tan32(0.0) == 0.0); | 105 | expect(tan_(f32, 0.0) == 0.0); |
| 160 | expect(tan32(-0.0) == -0.0); | 106 | expect(tan_(f32, -0.0) == -0.0); |
| 161 | expect(math.isNan(tan32(math.inf(f32)))); | 107 | expect(math.isNan(tan_(f32, math.inf(f32)))); |
| 162 | expect(math.isNan(tan32(-math.inf(f32)))); | 108 | expect(math.isNan(tan_(f32, -math.inf(f32)))); |
| 163 | expect(math.isNan(tan32(math.nan(f32)))); | 109 | expect(math.isNan(tan_(f32, math.nan(f32)))); |
| 164 | } | 110 | } |
| 165 | 111 | ||
| 166 | test "math.tan64.special" { | 112 | test "math.tan64.special" { |
| 167 | expect(tan64(0.0) == 0.0); | 113 | expect(tan_(f64, 0.0) == 0.0); |
| 168 | expect(tan64(-0.0) == -0.0); | 114 | expect(tan_(f64, -0.0) == -0.0); |
| 169 | expect(math.isNan(tan64(math.inf(f64)))); | 115 | expect(math.isNan(tan_(f64, math.inf(f64)))); |
| 170 | expect(math.isNan(tan64(-math.inf(f64)))); | 116 | expect(math.isNan(tan_(f64, -math.inf(f64)))); |
| 171 | expect(math.isNan(tan64(math.nan(f64)))); | 117 | expect(math.isNan(tan_(f64, math.nan(f64)))); |
| 172 | } | 118 | } |