authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-06-19 14:36:33-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-06-19 14:36:33-04:00
logc9fc8bd802f5ed52c4cc78b93f18fc5dc9b6bb7f
tree8ddb992d7c1b4ede1b6a99e32fad16c1a476e0c1
parent799c69910172a7248ab9db366e6e3a6556e7d626

workaround for llvm bug

See #393 for details

46 files changed, 474 insertions(+), 841 deletions(-)

src/codegen.cpp+1
......@@ -438,6 +438,7 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) {
438438 }
439439
440440 addLLVMFnAttr(fn_table_entry->llvm_value, "nounwind");
441 addLLVMFnAttr(fn_table_entry->llvm_value, "nobuiltin");
441442 if (g->build_mode == BuildModeDebug && fn_table_entry->fn_inline != FnInlineAlways) {
442443 ZigLLVMAddFunctionAttr(fn_table_entry->llvm_value, "no-frame-pointer-elim", "true");
443444 ZigLLVMAddFunctionAttr(fn_table_entry->llvm_value, "no-frame-pointer-elim-non-leaf", nullptr);
std/math/acos.zig+9-6
......@@ -1,7 +1,10 @@
11const math = @import("index.zig");
22const assert = @import("../debug.zig").assert;
33
4pub fn acos(x: var) -> @typeOf(x) {
4pub const acos = acos_workaround;
5
6// TODO issue #393
7pub fn acos_workaround(x: var) -> @typeOf(x) {
58 const T = @typeOf(x);
69 switch (T) {
710 f32 => @inlineCall(acos32, x),
......@@ -137,12 +140,12 @@ fn acos64(x: f64) -> f64 {
137140 2 * (df + w)
138141}
139142
140test "acos" {
141 assert(acos(f32(0.0)) == acos32(0.0));
142 assert(acos(f64(0.0)) == acos64(0.0));
143test "math.acos" {
144 assert(acos_workaround(f32(0.0)) == acos32(0.0));
145 assert(acos_workaround(f64(0.0)) == acos64(0.0));
143146}
144147
145test "acos32" {
148test "math.acos32" {
146149 const epsilon = 0.000001;
147150
148151 assert(math.approxEq(f32, acos32(0.0), 1.570796, epsilon));
......@@ -153,7 +156,7 @@ test "acos32" {
153156 assert(math.approxEq(f32, acos32(-0.2), 1.772154, epsilon));
154157}
155158
156test "acos64" {
159test "math.acos64" {
157160 const epsilon = 0.000001;
158161
159162 assert(math.approxEq(f64, acos64(0.0), 1.570796, epsilon));
std/math/acosh.zig+21-18
......@@ -1,17 +1,20 @@
11const math = @import("index.zig");
22const assert = @import("../debug.zig").assert;
33
4pub fn acosh(x: var) -> @typeOf(x) {
4pub const acosh = acosh_workaround;
5
6// TODO issue #393
7pub fn acosh_workaround(x: var) -> @typeOf(x) {
58 const T = @typeOf(x);
69 switch (T) {
7 f32 => @inlineCall(acoshf, x),
8 f64 => @inlineCall(acoshd, x),
10 f32 => @inlineCall(acosh32, x),
11 f64 => @inlineCall(acosh64, x),
912 else => @compileError("acosh not implemented for " ++ @typeName(T)),
1013 }
1114}
1215
1316// acosh(x) = log(x + sqrt(x * x - 1))
14fn acoshf(x: f32) -> f32 {
17fn acosh32(x: f32) -> f32 {
1518 const u = @bitCast(u32, x);
1619 const i = u & 0x7FFFFFFF;
1720
......@@ -29,7 +32,7 @@ fn acoshf(x: f32) -> f32 {
2932 }
3033}
3134
32fn acoshd(x: f64) -> f64 {
35fn acosh64(x: f64) -> f64 {
3336 const u = @bitCast(u64, x);
3437 const e = (u >> 52) & 0x7FF;
3538
......@@ -47,25 +50,25 @@ fn acoshd(x: f64) -> f64 {
4750 }
4851}
4952
50test "acosh" {
51 assert(acosh(f32(1.5)) == acoshf(1.5));
52 assert(acosh(f64(1.5)) == acoshd(1.5));
53test "math.acosh" {
54 assert(acosh_workaround(f32(1.5)) == acosh32(1.5));
55 assert(acosh_workaround(f64(1.5)) == acosh64(1.5));
5356}
5457
55test "acoshf" {
58test "math.acosh32" {
5659 const epsilon = 0.000001;
5760
58 assert(math.approxEq(f32, acoshf(1.5), 0.962424, epsilon));
59 assert(math.approxEq(f32, acoshf(37.45), 4.315976, epsilon));
60 assert(math.approxEq(f32, acoshf(89.123), 5.183133, epsilon));
61 assert(math.approxEq(f32, acoshf(123123.234375), 12.414088, epsilon));
61 assert(math.approxEq(f32, acosh32(1.5), 0.962424, epsilon));
62 assert(math.approxEq(f32, acosh32(37.45), 4.315976, epsilon));
63 assert(math.approxEq(f32, acosh32(89.123), 5.183133, epsilon));
64 assert(math.approxEq(f32, acosh32(123123.234375), 12.414088, epsilon));
6265}
6366
64test "acoshd" {
67test "math.acosh64" {
6568 const epsilon = 0.000001;
6669
67 assert(math.approxEq(f64, acoshd(1.5), 0.962424, epsilon));
68 assert(math.approxEq(f64, acoshd(37.45), 4.315976, epsilon));
69 assert(math.approxEq(f64, acoshd(89.123), 5.183133, epsilon));
70 assert(math.approxEq(f64, acoshd(123123.234375), 12.414088, epsilon));
70 assert(math.approxEq(f64, acosh64(1.5), 0.962424, epsilon));
71 assert(math.approxEq(f64, acosh64(37.45), 4.315976, epsilon));
72 assert(math.approxEq(f64, acosh64(89.123), 5.183133, epsilon));
73 assert(math.approxEq(f64, acosh64(123123.234375), 12.414088, epsilon));
7174}
std/math/asin.zig+9-6
......@@ -1,7 +1,10 @@
11const math = @import("index.zig");
22const assert = @import("../debug.zig").assert;
33
4pub fn asin(x: var) -> @typeOf(x) {
4pub const asin = asin_workaround;
5
6// TODO issue #393
7pub fn asin_workaround(x: var) -> @typeOf(x) {
58 const T = @typeOf(x);
69 switch (T) {
710 f32 => @inlineCall(asin32, x),
......@@ -129,12 +132,12 @@ fn asin64(x: f64) -> f64 {
129132 }
130133}
131134
132test "asin" {
133 assert(asin(f32(0.0)) == asin32(0.0));
134 assert(asin(f64(0.0)) == asin64(0.0));
135test "math.asin" {
136 assert(asin_workaround(f32(0.0)) == asin32(0.0));
137 assert(asin_workaround(f64(0.0)) == asin64(0.0));
135138}
136139
137test "asin32" {
140test "math.asin32" {
138141 const epsilon = 0.000001;
139142
140143 assert(math.approxEq(f32, asin32(0.0), 0.0, epsilon));
......@@ -145,7 +148,7 @@ test "asin32" {
145148 assert(math.approxEq(f32, asin32(0.8923), 1.102415, epsilon));
146149}
147150
148test "asin64" {
151test "math.asin64" {
149152 const epsilon = 0.000001;
150153
151154 assert(math.approxEq(f64, asin64(0.0), 0.0, epsilon));
std/math/asinh.zig+27-24
......@@ -1,17 +1,20 @@
11const math = @import("index.zig");
22const assert = @import("../debug.zig").assert;
33
4pub fn asinh(x: var) -> @typeOf(x) {
4pub const asinh = asinh_workaround;
5
6// TODO issue #393
7pub fn asinh_workaround(x: var) -> @typeOf(x) {
58 const T = @typeOf(x);
69 switch (T) {
7 f32 => @inlineCall(asinhf, x),
8 f64 => @inlineCall(asinhd, x),
10 f32 => @inlineCall(asinh32, x),
11 f64 => @inlineCall(asinh64, x),
912 else => @compileError("asinh not implemented for " ++ @typeName(T)),
1013 }
1114}
1215
1316// asinh(x) = sign(x) * log(|x| + sqrt(x * x + 1)) ~= x - x^3/6 + o(x^5)
14fn asinhf(x: f32) -> f32 {
17fn asinh32(x: f32) -> f32 {
1518 const u = @bitCast(u32, x);
1619 const i = u & 0x7FFFFFFF;
1720 const s = i >> 31;
......@@ -38,7 +41,7 @@ fn asinhf(x: f32) -> f32 {
3841 if (s != 0) -rx else rx
3942}
4043
41fn asinhd(x: f64) -> f64 {
44fn asinh64(x: f64) -> f64 {
4245 const u = @bitCast(u64, x);
4346 const e = (u >> 52) & 0x7FF;
4447 const s = u >> 63;
......@@ -65,31 +68,31 @@ fn asinhd(x: f64) -> f64 {
6568 if (s != 0) -rx else rx
6669}
6770
68test "asinh" {
69 assert(asinh(f32(0.0)) == asinhf(0.0));
70 assert(asinh(f64(0.0)) == asinhd(0.0));
71test "math.asinh" {
72 assert(asinh_workaround(f32(0.0)) == asinh32(0.0));
73 assert(asinh_workaround(f64(0.0)) == asinh64(0.0));
7174}
7275
73test "asinhf" {
76test "math.asinh32" {
7477 const epsilon = 0.000001;
7578
76 assert(math.approxEq(f32, asinhf(0.0), 0.0, epsilon));
77 assert(math.approxEq(f32, asinhf(0.2), 0.198690, epsilon));
78 assert(math.approxEq(f32, asinhf(0.8923), 0.803133, epsilon));
79 assert(math.approxEq(f32, asinhf(1.5), 1.194763, epsilon));
80 assert(math.approxEq(f32, asinhf(37.45), 4.316332, epsilon));
81 assert(math.approxEq(f32, asinhf(89.123), 5.183196, epsilon));
82 assert(math.approxEq(f32, asinhf(123123.234375), 12.414088, epsilon));
79 assert(math.approxEq(f32, asinh32(0.0), 0.0, epsilon));
80 assert(math.approxEq(f32, asinh32(0.2), 0.198690, epsilon));
81 assert(math.approxEq(f32, asinh32(0.8923), 0.803133, epsilon));
82 assert(math.approxEq(f32, asinh32(1.5), 1.194763, epsilon));
83 assert(math.approxEq(f32, asinh32(37.45), 4.316332, epsilon));
84 assert(math.approxEq(f32, asinh32(89.123), 5.183196, epsilon));
85 assert(math.approxEq(f32, asinh32(123123.234375), 12.414088, epsilon));
8386}
8487
85test "asinhd" {
88test "math.asinh64" {
8689 const epsilon = 0.000001;
8790
88 assert(math.approxEq(f64, asinhd(0.0), 0.0, epsilon));
89 assert(math.approxEq(f64, asinhd(0.2), 0.198690, epsilon));
90 assert(math.approxEq(f64, asinhd(0.8923), 0.803133, epsilon));
91 assert(math.approxEq(f64, asinhd(1.5), 1.194763, epsilon));
92 assert(math.approxEq(f64, asinhd(37.45), 4.316332, epsilon));
93 assert(math.approxEq(f64, asinhd(89.123), 5.183196, epsilon));
94 assert(math.approxEq(f64, asinhd(123123.234375), 12.414088, epsilon));
91 assert(math.approxEq(f64, asinh64(0.0), 0.0, epsilon));
92 assert(math.approxEq(f64, asinh64(0.2), 0.198690, epsilon));
93 assert(math.approxEq(f64, asinh64(0.8923), 0.803133, epsilon));
94 assert(math.approxEq(f64, asinh64(1.5), 1.194763, epsilon));
95 assert(math.approxEq(f64, asinh64(37.45), 4.316332, epsilon));
96 assert(math.approxEq(f64, asinh64(89.123), 5.183196, epsilon));
97 assert(math.approxEq(f64, asinh64(123123.234375), 12.414088, epsilon));
9598}
std/math/atan.zig+9-6
......@@ -1,7 +1,10 @@
11const math = @import("index.zig");
22const assert = @import("../debug.zig").assert;
33
4pub fn atan(x: var) -> @typeOf(x) {
4// TODO issue #393
5pub const atan = atan_workaround;
6
7pub fn atan_workaround(x: var) -> @typeOf(x) {
58 const T = @typeOf(x);
69 switch (T) {
710 f32 => @inlineCall(atan32, x),
......@@ -201,12 +204,12 @@ fn atan64(x_: f64) -> f64 {
201204 }
202205}
203206
204test "atan" {
205 assert(atan(f32(0.2)) == atan32(0.2));
206 assert(atan(f64(0.2)) == atan64(0.2));
207test "math.atan" {
208 assert(atan_workaround(f32(0.2)) == atan32(0.2));
209 assert(atan_workaround(f64(0.2)) == atan64(0.2));
207210}
208211
209test "atan32" {
212test "math.atan32" {
210213 const epsilon = 0.000001;
211214
212215 assert(math.approxEq(f32, atan32(0.2), 0.197396, epsilon));
......@@ -216,7 +219,7 @@ test "atan32" {
216219 assert(math.approxEq(f32, atan32(1.5), 0.982794, epsilon));
217220}
218221
219test "atan64" {
222test "math.atan64" {
220223 const epsilon = 0.000001;
221224
222225 assert(math.approxEq(f64, atan64(0.2), 0.197396, epsilon));
std/math/atan2.zig+27-24
......@@ -1,15 +1,18 @@
11const math = @import("index.zig");
22const assert = @import("../debug.zig").assert;
33
4pub fn atan2(comptime T: type, x: T, y: T) -> T {
4pub const atan2 = atan2_workaround;
5
6// TODO issue #393
7pub fn atan2_workaround(comptime T: type, x: T, y: T) -> T {
58 switch (T) {
6 f32 => @inlineCall(atan2f, x, y),
7 f64 => @inlineCall(atan2d, x, y),
9 f32 => @inlineCall(atan2_32, x, y),
10 f64 => @inlineCall(atan2_64, x, y),
811 else => @compileError("atan2 not implemented for " ++ @typeName(T)),
912 }
1013}
1114
12fn atan2f(y: f32, x: f32) -> f32 {
15fn atan2_32(y: f32, x: f32) -> f32 {
1316 const pi: f32 = 3.1415927410e+00;
1417 const pi_lo: f32 = -8.7422776573e-08;
1518
......@@ -94,7 +97,7 @@ fn atan2f(y: f32, x: f32) -> f32 {
9497 }
9598}
9699
97fn atan2d(y: f64, x: f64) -> f64 {
100fn atan2_64(y: f64, x: f64) -> f64 {
98101 const pi: f64 = 3.1415926535897931160E+00;
99102 const pi_lo: f64 = 1.2246467991473531772E-16;
100103
......@@ -184,31 +187,31 @@ fn atan2d(y: f64, x: f64) -> f64 {
184187 }
185188}
186189
187test "atan2" {
188 assert(atan2(f32, 0.2, 0.21) == atan2f(0.2, 0.21));
189 assert(atan2(f64, 0.2, 0.21) == atan2d(0.2, 0.21));
190test "math.atan2" {
191 assert(atan2_workaround(f32, 0.2, 0.21) == atan2_32(0.2, 0.21));
192 assert(atan2_workaround(f64, 0.2, 0.21) == atan2_64(0.2, 0.21));
190193}
191194
192test "atan2f" {
195test "math.atan2_32" {
193196 const epsilon = 0.000001;
194197
195 assert(math.approxEq(f32, atan2f(0.0, 0.0), 0.0, epsilon));
196 assert(math.approxEq(f32, atan2f(0.2, 0.2), 0.785398, epsilon));
197 assert(math.approxEq(f32, atan2f(-0.2, 0.2), -0.785398, epsilon));
198 assert(math.approxEq(f32, atan2f(0.2, -0.2), 2.356194, epsilon));
199 assert(math.approxEq(f32, atan2f(-0.2, -0.2), -2.356194, epsilon));
200 assert(math.approxEq(f32, atan2f(0.34, -0.4), 2.437099, epsilon));
201 assert(math.approxEq(f32, atan2f(0.34, 1.243), 0.267001, epsilon));
198 assert(math.approxEq(f32, atan2_32(0.0, 0.0), 0.0, epsilon));
199 assert(math.approxEq(f32, atan2_32(0.2, 0.2), 0.785398, epsilon));
200 assert(math.approxEq(f32, atan2_32(-0.2, 0.2), -0.785398, epsilon));
201 assert(math.approxEq(f32, atan2_32(0.2, -0.2), 2.356194, epsilon));
202 assert(math.approxEq(f32, atan2_32(-0.2, -0.2), -2.356194, epsilon));
203 assert(math.approxEq(f32, atan2_32(0.34, -0.4), 2.437099, epsilon));
204 assert(math.approxEq(f32, atan2_32(0.34, 1.243), 0.267001, epsilon));
202205}
203206
204test "atan2d" {
207test "math.atan2_64" {
205208 const epsilon = 0.000001;
206209
207 assert(math.approxEq(f64, atan2d(0.0, 0.0), 0.0, epsilon));
208 assert(math.approxEq(f64, atan2d(0.2, 0.2), 0.785398, epsilon));
209 assert(math.approxEq(f64, atan2d(-0.2, 0.2), -0.785398, epsilon));
210 assert(math.approxEq(f64, atan2d(0.2, -0.2), 2.356194, epsilon));
211 assert(math.approxEq(f64, atan2d(-0.2, -0.2), -2.356194, epsilon));
212 assert(math.approxEq(f64, atan2d(0.34, -0.4), 2.437099, epsilon));
213 assert(math.approxEq(f64, atan2d(0.34, 1.243), 0.267001, epsilon));
210 assert(math.approxEq(f64, atan2_64(0.0, 0.0), 0.0, epsilon));
211 assert(math.approxEq(f64, atan2_64(0.2, 0.2), 0.785398, epsilon));
212 assert(math.approxEq(f64, atan2_64(-0.2, 0.2), -0.785398, epsilon));
213 assert(math.approxEq(f64, atan2_64(0.2, -0.2), 2.356194, epsilon));
214 assert(math.approxEq(f64, atan2_64(-0.2, -0.2), -2.356194, epsilon));
215 assert(math.approxEq(f64, atan2_64(0.34, -0.4), 2.437099, epsilon));
216 assert(math.approxEq(f64, atan2_64(0.34, 1.243), 0.267001, epsilon));
214217}
std/math/atanh.zig+19-16
......@@ -1,17 +1,20 @@
11const math = @import("index.zig");
22const assert = @import("../debug.zig").assert;
33
4pub fn atanh(x: var) -> @typeOf(x) {
4// TODO issue #393
5pub const atanh = atanh_workaround;
6
7pub fn atanh_workaround(x: var) -> @typeOf(x) {
58 const T = @typeOf(x);
69 switch (T) {
7 f32 => @inlineCall(atanhf, x),
8 f64 => @inlineCall(atanhd, x),
10 f32 => @inlineCall(atanh_32, x),
11 f64 => @inlineCall(atanh_64, x),
912 else => @compileError("atanh not implemented for " ++ @typeName(T)),
1013 }
1114}
1215
1316// atanh(x) = log((1 + x) / (1 - x)) / 2 = log1p(2x / (1 - x)) / 2 ~= x + x^3 / 3 + o(x^5)
14fn atanhf(x: f32) -> f32 {
17fn atanh_32(x: f32) -> f32 {
1518 const u = @bitCast(u32, x);
1619 const i = u & 0x7FFFFFFF;
1720 const s = u >> 31;
......@@ -37,7 +40,7 @@ fn atanhf(x: f32) -> f32 {
3740 if (s != 0) -y else y
3841}
3942
40fn atanhd(x: f64) -> f64 {
43fn atanh_64(x: f64) -> f64 {
4144 const u = @bitCast(u64, x);
4245 const e = (u >> 52) & 0x7FF;
4346 const s = u >> 63;
......@@ -63,23 +66,23 @@ fn atanhd(x: f64) -> f64 {
6366 if (s != 0) -y else y
6467}
6568
66test "atanh" {
67 assert(atanh(f32(0.0)) == atanhf(0.0));
68 assert(atanh(f64(0.0)) == atanhd(0.0));
69test "math.atanh" {
70 assert(atanh(f32(0.0)) == atanh_32(0.0));
71 assert(atanh(f64(0.0)) == atanh_64(0.0));
6972}
7073
71test "atanhf" {
74test "math.atanh_32" {
7275 const epsilon = 0.000001;
7376
74 assert(math.approxEq(f32, atanhf(0.0), 0.0, epsilon));
75 assert(math.approxEq(f32, atanhf(0.2), 0.202733, epsilon));
76 assert(math.approxEq(f32, atanhf(0.8923), 1.433099, epsilon));
77 assert(math.approxEq(f32, atanh_32(0.0), 0.0, epsilon));
78 assert(math.approxEq(f32, atanh_32(0.2), 0.202733, epsilon));
79 assert(math.approxEq(f32, atanh_32(0.8923), 1.433099, epsilon));
7780}
7881
79test "atanhd" {
82test "math.atanh_64" {
8083 const epsilon = 0.000001;
8184
82 assert(math.approxEq(f64, atanhd(0.0), 0.0, epsilon));
83 assert(math.approxEq(f64, atanhd(0.2), 0.202733, epsilon));
84 assert(math.approxEq(f64, atanhd(0.8923), 1.433099, epsilon));
85 assert(math.approxEq(f64, atanh_64(0.0), 0.0, epsilon));
86 assert(math.approxEq(f64, atanh_64(0.2), 0.202733, epsilon));
87 assert(math.approxEq(f64, atanh_64(0.8923), 1.433099, epsilon));
8588}
std/math/cbrt.zig+7-4
......@@ -1,7 +1,10 @@
11const math = @import("index.zig");
22const assert = @import("../debug.zig").assert;
33
4pub fn cbrt(x: var) -> @typeOf(x) {
4// TODO issue #393
5pub const cbrt = cbrt_workaround;
6
7pub fn cbrt_workaround(x: var) -> @typeOf(x) {
58 const T = @typeOf(x);
69 switch (T) {
710 f32 => @inlineCall(cbrt32, x),
......@@ -106,12 +109,12 @@ fn cbrt64(x: f64) -> f64 {
106109 t + t * q
107110}
108111
109test "cbrt" {
112test "math.cbrt" {
110113 assert(cbrt(f32(0.0)) == cbrt32(0.0));
111114 assert(cbrt(f64(0.0)) == cbrt64(0.0));
112115}
113116
114test "cbrt32" {
117test "math.cbrt32" {
115118 const epsilon = 0.000001;
116119
117120 assert(cbrt32(0.0) == 0.0);
......@@ -122,7 +125,7 @@ test "cbrt32" {
122125 assert(math.approxEq(f32, cbrt32(123123.234375), 49.748501, epsilon));
123126}
124127
125test "cbrt64" {
128test "math.cbrt64" {
126129 const epsilon = 0.000001;
127130
128131 assert(cbrt64(0.0) == 0.0);
std/math/ceil.zig+7-4
......@@ -2,7 +2,10 @@ const builtin = @import("builtin");
22const math = @import("index.zig");
33const assert = @import("../debug.zig").assert;
44
5pub fn ceil(x: var) -> @typeOf(x) {
5// TODO issue #393
6pub const ceil = ceil_workaround;
7
8pub fn ceil_workaround(x: var) -> @typeOf(x) {
69 const T = @typeOf(x);
710 switch (T) {
811 f32 => @inlineCall(ceil32, x),
......@@ -71,18 +74,18 @@ fn ceil64(x: f64) -> f64 {
7174 }
7275}
7376
74test "ceil" {
77test "math.ceil" {
7578 assert(ceil(f32(0.0)) == ceil32(0.0));
7679 assert(ceil(f64(0.0)) == ceil64(0.0));
7780}
7881
79test "ceil32" {
82test "math.ceil32" {
8083 assert(ceil32(1.3) == 2.0);
8184 assert(ceil32(-1.3) == -1.0);
8285 assert(ceil32(0.2) == 1.0);
8386}
8487
85test "ceil64" {
88test "math.ceil64" {
8689 assert(ceil64(1.3) == 2.0);
8790 assert(ceil64(-1.3) == -1.0);
8891 assert(ceil64(0.2) == 1.0);
std/math/copysign.zig+7-4
......@@ -1,7 +1,10 @@
11const math = @import("index.zig");
22const assert = @import("../debug.zig").assert;
33
4pub fn copysign(comptime T: type, x: T, y: T) -> T {
4// TODO issue #393
5pub const copysign = copysign_workaround;
6
7pub fn copysign_workaround(comptime T: type, x: T, y: T) -> T {
58 switch (T) {
69 f32 => @inlineCall(copysign32, x, y),
710 f64 => @inlineCall(copysign64, x, y),
......@@ -27,19 +30,19 @@ fn copysign64(x: f64, y: f64) -> f64 {
2730 @bitCast(f64, h1 | h2)
2831}
2932
30test "copysign" {
33test "math.copysign" {
3134 assert(copysign(f32, 1.0, 1.0) == copysign32(1.0, 1.0));
3235 assert(copysign(f64, 1.0, 1.0) == copysign64(1.0, 1.0));
3336}
3437
35test "copysign32" {
38test "math.copysign32" {
3639 assert(copysign32(5.0, 1.0) == 5.0);
3740 assert(copysign32(5.0, -1.0) == -5.0);
3841 assert(copysign32(-5.0, -1.0) == -5.0);
3942 assert(copysign32(-5.0, 1.0) == 5.0);
4043}
4144
42test "copysign64" {
45test "math.copysign64" {
4346 assert(copysign64(5.0, 1.0) == 5.0);
4447 assert(copysign64(5.0, -1.0) == -5.0);
4548 assert(copysign64(-5.0, -1.0) == -5.0);
std/math/cos.zig+8-4
......@@ -1,7 +1,11 @@
11const math = @import("index.zig");
22const assert = @import("../debug.zig").assert;
33
4pub fn cos(x: var) -> @typeOf(x) {
4
5// TODO issue #393
6pub const cos = cos_workaround;
7
8pub fn cos_workaround(x: var) -> @typeOf(x) {
59 const T = @typeOf(x);
610 switch (T) {
711 f32 => @inlineCall(cos32, x),
......@@ -133,12 +137,12 @@ fn cos64(x_: f64) -> f64 {
133137 }
134138}
135139
136test "cos" {
140test "math.cos" {
137141 assert(cos(f32(0.0)) == cos32(0.0));
138142 assert(cos(f64(0.0)) == cos64(0.0));
139143}
140144
141test "cos32" {
145test "math.cos32" {
142146 const epsilon = 0.000001;
143147
144148 assert(math.approxEq(f32, cos32(0.0), 1.0, epsilon));
......@@ -149,7 +153,7 @@ test "cos32" {
149153 assert(math.approxEq(f32, cos32(89.123), 0.400798, epsilon));
150154}
151155
152test "cos64" {
156test "math.cos64" {
153157 const epsilon = 0.000001;
154158
155159 assert(math.approxEq(f64, cos64(0.0), 1.0, epsilon));
std/math/cosh.zig+21-18
......@@ -2,11 +2,14 @@ const math = @import("index.zig");
22const expo2 = @import("_expo2.zig").expo2;
33const assert = @import("../debug.zig").assert;
44
5pub fn cosh(x: var) -> @typeOf(x) {
5// TODO issue #393
6pub const cosh = cosh_workaround;
7
8pub fn cosh_workaround(x: var) -> @typeOf(x) {
69 const T = @typeOf(x);
710 switch (T) {
8 f32 => @inlineCall(coshf, x),
9 f64 => @inlineCall(coshd, x),
11 f32 => @inlineCall(cosh32, x),
12 f64 => @inlineCall(cosh64, x),
1013 else => @compileError("cosh not implemented for " ++ @typeName(T)),
1114 }
1215}
......@@ -14,7 +17,7 @@ pub fn cosh(x: var) -> @typeOf(x) {
1417// cosh(x) = (exp(x) + 1 / exp(x)) / 2
1518// = 1 + 0.5 * (exp(x) - 1) * (exp(x) - 1) / exp(x)
1619// = 1 + (x * x) / 2 + o(x^4)
17fn coshf(x: f32) -> f32 {
20fn cosh32(x: f32) -> f32 {
1821 const u = @bitCast(u32, x);
1922 const ux = u & 0x7FFFFFFF;
2023 const ax = @bitCast(f32, ux);
......@@ -39,7 +42,7 @@ fn coshf(x: f32) -> f32 {
3942 expo2(ax)
4043}
4144
42fn coshd(x: f64) -> f64 {
45fn cosh64(x: f64) -> f64 {
4346 const u = @bitCast(u64, x);
4447 const w = u32(u >> 32);
4548 const ax = @bitCast(f64, u & (@maxValue(u64) >> 1));
......@@ -67,25 +70,25 @@ fn coshd(x: f64) -> f64 {
6770 expo2(ax)
6871}
6972
70test "cosh" {
71 assert(cosh(f32(1.5)) == coshf(1.5));
72 assert(cosh(f64(1.5)) == coshd(1.5));
73test "math.cosh" {
74 assert(cosh(f32(1.5)) == cosh32(1.5));
75 assert(cosh(f64(1.5)) == cosh64(1.5));
7376}
7477
75test "coshf" {
78test "math.cosh32" {
7679 const epsilon = 0.000001;
7780
78 assert(math.approxEq(f32, coshf(0.0), 1.0, epsilon));
79 assert(math.approxEq(f32, coshf(0.2), 1.020067, epsilon));
80 assert(math.approxEq(f32, coshf(0.8923), 1.425225, epsilon));
81 assert(math.approxEq(f32, coshf(1.5), 2.352410, epsilon));
81 assert(math.approxEq(f32, cosh32(0.0), 1.0, epsilon));
82 assert(math.approxEq(f32, cosh32(0.2), 1.020067, epsilon));
83 assert(math.approxEq(f32, cosh32(0.8923), 1.425225, epsilon));
84 assert(math.approxEq(f32, cosh32(1.5), 2.352410, epsilon));
8285}
8386
84test "coshd" {
87test "math.cosh64" {
8588 const epsilon = 0.000001;
8689
87 assert(math.approxEq(f64, coshd(0.0), 1.0, epsilon));
88 assert(math.approxEq(f64, coshd(0.2), 1.020067, epsilon));
89 assert(math.approxEq(f64, coshd(0.8923), 1.425225, epsilon));
90 assert(math.approxEq(f64, coshd(1.5), 2.352410, epsilon));
90 assert(math.approxEq(f64, cosh64(0.0), 1.0, epsilon));
91 assert(math.approxEq(f64, cosh64(0.2), 1.020067, epsilon));
92 assert(math.approxEq(f64, cosh64(0.8923), 1.425225, epsilon));
93 assert(math.approxEq(f64, cosh64(1.5), 2.352410, epsilon));
9194}
std/math/exp.zig+7-4
......@@ -1,7 +1,10 @@
11const math = @import("index.zig");
22const assert = @import("../debug.zig").assert;
33
4pub fn exp(x: var) -> @typeOf(x) {
4// TODO issue #393
5pub const exp = exp_workaround;
6
7pub fn exp_workaround(x: var) -> @typeOf(x) {
58 const T = @typeOf(x);
69 switch (T) {
710 f32 => @inlineCall(exp32, x),
......@@ -165,12 +168,12 @@ fn exp64(x_: f64) -> f64 {
165168 }
166169}
167170
168test "exp" {
171test "math.exp" {
169172 assert(exp(f32(0.0)) == exp32(0.0));
170173 assert(exp(f64(0.0)) == exp64(0.0));
171174}
172175
173test "exp32" {
176test "math.exp32" {
174177 const epsilon = 0.000001;
175178
176179 assert(exp32(0.0) == 1.0);
......@@ -180,7 +183,7 @@ test "exp32" {
180183 assert(math.approxEq(f32, exp32(1.5), 4.481689, epsilon));
181184}
182185
183test "exp64" {
186test "math.exp64" {
184187 const epsilon = 0.000001;
185188
186189 assert(exp64(0.0) == 1.0);
std/math/exp2.zig+23-20
......@@ -1,11 +1,14 @@
11const math = @import("index.zig");
22const assert = @import("../debug.zig").assert;
33
4pub fn exp2(x: var) -> @typeOf(x) {
4// TODO issue #393
5pub const exp2 = exp2_workaround;
6
7pub fn exp2_workaround(x: var) -> @typeOf(x) {
58 const T = @typeOf(x);
69 switch (T) {
7 f32 => @inlineCall(exp2f, x),
8 f64 => @inlineCall(exp2d, x),
10 f32 => @inlineCall(exp2_32, x),
11 f64 => @inlineCall(exp2_64, x),
912 else => @compileError("exp2 not implemented for " ++ @typeName(T)),
1013 }
1114}
......@@ -29,7 +32,7 @@ const exp2ft = []const f64 {
2932 0x1.5ab07dd485429p+0,
3033};
3134
32fn exp2f(x: f32) -> f32 {
35fn exp2_32(x: f32) -> f32 {
3336 @setFloatMode(this, @import("builtin").FloatMode.Strict);
3437
3538 const tblsiz = u32(exp2ft.len);
......@@ -346,7 +349,7 @@ const exp2dt = []f64 {
346349 0x1.690f4b19e9471p+0, -0x1.9780p-45,
347350};
348351
349fn exp2d(x: f64) -> f64 {
352fn exp2_64(x: f64) -> f64 {
350353 @setFloatMode(this, @import("builtin").FloatMode.Strict);
351354
352355 const tblsiz = u32(exp2dt.len / 2);
......@@ -407,27 +410,27 @@ fn exp2d(x: f64) -> f64 {
407410 math.scalbn(r, ik)
408411}
409412
410test "exp2" {
411 assert(exp2(f32(0.8923)) == exp2f(0.8923));
412 assert(exp2(f64(0.8923)) == exp2d(0.8923));
413test "math.exp2" {
414 assert(exp2(f32(0.8923)) == exp2_32(0.8923));
415 assert(exp2(f64(0.8923)) == exp2_64(0.8923));
413416}
414417
415test "exp2f" {
418test "math.exp2_32" {
416419 const epsilon = 0.000001;
417420
418 assert(exp2f(0.0) == 1.0);
419 assert(math.approxEq(f32, exp2f(0.2), 1.148698, epsilon));
420 assert(math.approxEq(f32, exp2f(0.8923), 1.856133, epsilon));
421 assert(math.approxEq(f32, exp2f(1.5), 2.828427, epsilon));
422 assert(math.approxEq(f32, exp2f(37.45), 187747237888, epsilon));
421 assert(exp2_32(0.0) == 1.0);
422 assert(math.approxEq(f32, exp2_32(0.2), 1.148698, epsilon));
423 assert(math.approxEq(f32, exp2_32(0.8923), 1.856133, epsilon));
424 assert(math.approxEq(f32, exp2_32(1.5), 2.828427, epsilon));
425 assert(math.approxEq(f32, exp2_32(37.45), 187747237888, epsilon));
423426}
424427
425test "exp2d" {
428test "math.exp2_64" {
426429 const epsilon = 0.000001;
427430
428 assert(exp2d(0.0) == 1.0);
429 assert(math.approxEq(f64, exp2d(0.2), 1.148698, epsilon));
430 assert(math.approxEq(f64, exp2d(0.8923), 1.856133, epsilon));
431 assert(math.approxEq(f64, exp2d(1.5), 2.828427, epsilon));
432 // assert(math.approxEq(f64, exp2d(37.45), 18379273786760560.000000, epsilon));
431 assert(exp2_64(0.0) == 1.0);
432 assert(math.approxEq(f64, exp2_64(0.2), 1.148698, epsilon));
433 assert(math.approxEq(f64, exp2_64(0.8923), 1.856133, epsilon));
434 assert(math.approxEq(f64, exp2_64(1.5), 2.828427, epsilon));
435 // assert(math.approxEq(f64, exp2_64(37.45), 18379273786760560.000000, epsilon));
433436}
std/math/expm1.zig+23-20
......@@ -1,16 +1,19 @@
11const math = @import("index.zig");
22const assert = @import("../debug.zig").assert;
33
4pub fn expm1(x: var) -> @typeOf(x) {
4// TODO issue #393
5pub const expm1 = expm1_workaround;
6
7pub fn expm1_workaround(x: var) -> @typeOf(x) {
58 const T = @typeOf(x);
69 switch (T) {
7 f32 => @inlineCall(expm1f, x),
8 f64 => @inlineCall(expm1d, x),
10 f32 => @inlineCall(expm1_32, x),
11 f64 => @inlineCall(expm1_64, x),
912 else => @compileError("exp1m not implemented for " ++ @typeName(T)),
1013 }
1114}
1215
13fn expm1f(x_: f32) -> f32 {
16fn expm1_32(x_: f32) -> f32 {
1417 const o_threshold: f32 = 8.8721679688e+01;
1518 const ln2_hi: f32 = 6.9313812256e-01;
1619 const ln2_lo: f32 = 9.0580006145e-06;
......@@ -131,7 +134,7 @@ fn expm1f(x_: f32) -> f32 {
131134 }
132135}
133136
134fn expm1d(x_: f64) -> f64 {
137fn expm1_64(x_: f64) -> f64 {
135138 const o_threshold: f64 = 7.09782712893383973096e+02;
136139 const ln2_hi: f64 = 6.93147180369123816490e-01;
137140 const ln2_lo: f64 = 1.90821492927058770002e-10;
......@@ -256,27 +259,27 @@ fn expm1d(x_: f64) -> f64 {
256259 }
257260}
258261
259test "exp1m" {
260 assert(expm1(f32(0.0)) == expm1f(0.0));
261 assert(expm1(f64(0.0)) == expm1d(0.0));
262test "math.exp1m" {
263 assert(expm1(f32(0.0)) == expm1_32(0.0));
264 assert(expm1(f64(0.0)) == expm1_64(0.0));
262265}
263266
264test "expm1f" {
267test "math.expm1_32" {
265268 const epsilon = 0.000001;
266269
267 assert(expm1f(0.0) == 0.0);
268 assert(math.approxEq(f32, expm1f(0.0), 0.0, epsilon));
269 assert(math.approxEq(f32, expm1f(0.2), 0.221403, epsilon));
270 assert(math.approxEq(f32, expm1f(0.8923), 1.440737, epsilon));
271 assert(math.approxEq(f32, expm1f(1.5), 3.481689, epsilon));
270 assert(expm1_32(0.0) == 0.0);
271 assert(math.approxEq(f32, expm1_32(0.0), 0.0, epsilon));
272 assert(math.approxEq(f32, expm1_32(0.2), 0.221403, epsilon));
273 assert(math.approxEq(f32, expm1_32(0.8923), 1.440737, epsilon));
274 assert(math.approxEq(f32, expm1_32(1.5), 3.481689, epsilon));
272275}
273276
274test "expm1d" {
277test "math.expm1_64" {
275278 const epsilon = 0.000001;
276279
277 assert(expm1d(0.0) == 0.0);
278 assert(math.approxEq(f64, expm1d(0.0), 0.0, epsilon));
279 assert(math.approxEq(f64, expm1d(0.2), 0.221403, epsilon));
280 assert(math.approxEq(f64, expm1d(0.8923), 1.440737, epsilon));
281 assert(math.approxEq(f64, expm1d(1.5), 3.481689, epsilon));
280 assert(expm1_64(0.0) == 0.0);
281 assert(math.approxEq(f64, expm1_64(0.0), 0.0, epsilon));
282 assert(math.approxEq(f64, expm1_64(0.2), 0.221403, epsilon));
283 assert(math.approxEq(f64, expm1_64(0.8923), 1.440737, epsilon));
284 assert(math.approxEq(f64, expm1_64(1.5), 3.481689, epsilon));
282285}
std/math/fabs.zig+7-4
......@@ -1,7 +1,10 @@
11const math = @import("index.zig");
22const assert = @import("../debug.zig").assert;
33
4pub fn fabs(x: var) -> @typeOf(x) {
4// TODO issue #393
5pub const fabs = fabs_workaround;
6
7pub fn fabs_workaround(x: var) -> @typeOf(x) {
58 const T = @typeOf(x);
69 switch (T) {
710 f32 => @inlineCall(fabs32, x),
......@@ -22,17 +25,17 @@ fn fabs64(x: f64) -> f64 {
2225 @bitCast(f64, u)
2326}
2427
25test "fabs" {
28test "math.fabs" {
2629 assert(fabs(f32(1.0)) == fabs32(1.0));
2730 assert(fabs(f64(1.0)) == fabs64(1.0));
2831}
2932
30test "fabs32" {
33test "math.fabs32" {
3134 assert(fabs64(1.0) == 1.0);
3235 assert(fabs64(-1.0) == 1.0);
3336}
3437
35test "fabs64" {
38test "math.fabs64" {
3639 assert(fabs64(1.0) == 1.0);
3740 assert(fabs64(-1.0) == 1.0);
3841}
std/math/floor.zig+7-4
......@@ -2,7 +2,10 @@ const builtin = @import("builtin");
22const assert = @import("../debug.zig").assert;
33const math = @import("index.zig");
44
5pub fn floor(x: var) -> @typeOf(x) {
5// TODO issue #393
6pub const floor = floor_workaround;
7
8pub fn floor_workaround(x: var) -> @typeOf(x) {
69 const T = @typeOf(x);
710 switch (T) {
811 f32 => @inlineCall(floor32, x),
......@@ -71,18 +74,18 @@ fn floor64(x: f64) -> f64 {
7174 }
7275}
7376
74test "floor" {
77test "math.floor" {
7578 assert(floor(f32(1.3)) == floor32(1.3));
7679 assert(floor(f64(1.3)) == floor64(1.3));
7780}
7881
79test "floor32" {
82test "math.floor32" {
8083 assert(floor32(1.3) == 1.0);
8184 assert(floor32(-1.3) == -2.0);
8285 assert(floor32(0.2) == 0.0);
8386}
8487
85test "floor64" {
88test "math.floor64" {
8689 assert(floor64(1.3) == 1.0);
8790 assert(floor64(-1.3) == -2.0);
8891 assert(floor64(0.2) == 0.0);
std/math/fma.zig+7-4
......@@ -1,7 +1,10 @@
11const math = @import("index.zig");
22const assert = @import("../debug.zig").assert;
33
4pub fn fma(comptime T: type, x: T, y: T, z: T) -> T {
4// TODO issue #393
5pub const fma = fma_workaround;
6
7pub fn fma_workaround(comptime T: type, x: T, y: T, z: T) -> T {
58 switch (T) {
69 f32 => @inlineCall(fma32, x, y, z),
710 f64 => @inlineCall(fma64, x, y ,z),
......@@ -130,12 +133,12 @@ fn add_and_denorm(a: f64, b: f64, scale: i32) -> f64 {
130133 math.scalbn(sum.hi, scale)
131134}
132135
133test "fma" {
136test "math.fma" {
134137 assert(fma(f32, 0.0, 1.0, 1.0) == fma32(0.0, 1.0, 1.0));
135138 assert(fma(f64, 0.0, 1.0, 1.0) == fma64(0.0, 1.0, 1.0));
136139}
137140
138test "fma32" {
141test "math.fma32" {
139142 const epsilon = 0.000001;
140143
141144 assert(math.approxEq(f32, fma32(0.0, 5.0, 9.124), 9.124, epsilon));
......@@ -147,7 +150,7 @@ test "fma32" {
147150 assert(math.approxEq(f32, fma32(123123.234375, 5.0, 9.124), 615625.295875, epsilon));
148151}
149152
150test "fma64" {
153test "math.fma64" {
151154 const epsilon = 0.000001;
152155
153156 assert(math.approxEq(f64, fma64(0.0, 5.0, 9.124), 9.124, epsilon));
std/math/fmod.zig deleted-190
......@@ -1,190 +0,0 @@
1const math = @import("index.zig");
2const assert = @import("../debug.zig").assert;
3
4pub fn fmod(comptime T: type, x: T, y: T) -> T {
5 switch (T) {
6 f32 => @inlineCall(fmod32, x, y),
7 f64 => @inlineCall(fmod64, x, y),
8 else => @compileError("fmod not implemented for " ++ @typeName(T)),
9 }
10}
11
12fn fmod32(x: f32, y: f32) -> f32 {
13 var ux = @bitCast(u32, x);
14 var uy = @bitCast(u32, y);
15 var ex = i32(ux >> 23) & 0xFF;
16 var ey = i32(ux >> 23) & 0xFF;
17 const sx = ux & 0x80000000;
18
19 if (uy << 1 == 0 or math.isNan(y) or ex == 0xFF) {
20 return (x * y) / (x * y);
21 }
22 if (ux << 1 <= uy << 1) {
23 if (ux << 1 == uy << 1) {
24 return 0 * x;
25 } else {
26 return x;
27 }
28 }
29
30 // normalize x and y
31 if (ex == 0) {
32 var i = ux << 9;
33 while (i >> 31 == 0) : (i <<= 1) {
34 ex -= 1;
35 }
36 ux <<= u32(-ex + 1);
37 } else {
38 ux &= @maxValue(u32) >> 9;
39 ux |= 1 << 23;
40 }
41
42 if (ey == 0) {
43 var i = uy << 9;
44 while (i >> 31 == 0) : (i <<= 1) {
45 ey -= 1;
46 }
47 uy <<= u32(-ey + 1);
48 } else {
49 uy &= @maxValue(u32) >> 9;
50 uy |= 1 << 23;
51 }
52
53 // x mod y
54 while (ex > ey) : (ex -= 1) {
55 const i = ux - uy;
56 if (i >> 31 == 0) {
57 if (i == 0) {
58 return 0 * x;
59 }
60 ux = i;
61 }
62 ux <<= 1;
63 }
64 {
65 const i = ux - uy;
66 if (i >> 31 == 0) {
67 if (i == 0) {
68 return 0 * x;
69 }
70 ux = i;
71 }
72 }
73
74 while (ux >> 23 == 0) : (ux <<= 1) {
75 ex -= 1;
76 }
77
78 // scale result up
79 if (ex > 0) {
80 ux -= 1 << 23;
81 ux |= u32(ex) << 23;
82 } else {
83 ux >>= u32(-ex + 1);
84 }
85
86 ux |= sx;
87 @bitCast(f32, ux)
88}
89
90fn fmod64(x: f64, y: f64) -> f64 {
91 var ux = @bitCast(u64, x);
92 var uy = @bitCast(u64, y);
93 var ex = i32(ux >> 52) & 0x7FF;
94 var ey = i32(ux >> 52) & 0x7FF;
95 const sx = ux >> 63;
96
97 if (uy << 1 == 0 or math.isNan(y) or ex == 0x7FF) {
98 return (x * y) / (x * y);
99 }
100 if (ux << 1 <= uy << 1) {
101 if (ux << 1 == uy << 1) {
102 return 0 * x;
103 } else {
104 return x;
105 }
106 }
107
108 // normalize x and y
109 if (ex == 0) {
110 var i = ux << 12;
111 while (i >> 63 == 0) : (i <<= 1) {
112 ex -= 1;
113 }
114 ux <<= u64(-ex + 1);
115 } else {
116 ux &= @maxValue(u64) >> 12;
117 ux |= 1 << 52;
118 }
119
120 if (ey == 0) {
121 var i = uy << 12;
122 while (i >> 63 == 0) : (i <<= 1) {
123 ey -= 1;
124 }
125 uy <<= u64(-ey + 1);
126 } else {
127 uy &= @maxValue(u64) >> 12;
128 uy |= 1 << 52;
129 }
130
131 // x mod y
132 while (ex > ey) : (ex -= 1) {
133 const i = ux - uy;
134 if (i >> 63 == 0) {
135 if (i == 0) {
136 return 0 * x;
137 }
138 ux = i;
139 }
140 ux <<= 1;
141 }
142 {
143 const i = ux - uy;
144 if (i >> 63 == 0) {
145 if (i == 0) {
146 return 0 * x;
147 }
148 ux = i;
149 }
150 }
151
152 while (ux >> 52 == 0) : (ux <<= 1) {
153 ex -= 1;
154 }
155
156 // scale result up
157 if (ex > 0) {
158 ux -= 1 << 52;
159 ux |= u64(ex) << 52;
160 } else {
161 ux >>= u64(-ex + 1);
162 }
163
164 ux |= sx << 63;
165 @bitCast(f64, ux)
166}
167
168// duplicate symbol clash with `fmod` test name
169test "fmod_" {
170 assert(fmod(f32, 1.3, 2.5) == fmod32(1.3, 2.5));
171 assert(fmod(f64, 1.3, 2.5) == fmod64(1.3, 2.5));
172}
173
174test "fmod32" {
175 const epsilon = 0.000001;
176
177 assert(math.approxEq(f32, fmod32(5.2, 2.0), 1.2, epsilon));
178 assert(math.approxEq(f32, fmod32(18.5, 4.2), 1.7, epsilon));
179 assert(math.approxEq(f32, fmod32(23, 48.34), 23.0, epsilon));
180 assert(math.approxEq(f32, fmod32(123.340890, 2398.2314), 123.340889, epsilon));
181}
182
183test "fmod64" {
184 const epsilon = 0.000001;
185
186 assert(math.approxEq(f64, fmod64(5.2, 2.0), 1.2, epsilon));
187 assert(math.approxEq(f64, fmod64(18.5, 4.2), 1.7, epsilon));
188 assert(math.approxEq(f64, fmod64(23, 48.34), 23.0, epsilon));
189 assert(math.approxEq(f64, fmod64(123.340890, 2398.2314), 123.340889, epsilon));
190}
std/math/frexp.zig+7-4
......@@ -1,6 +1,9 @@
11const math = @import("index.zig");
22const assert = @import("../debug.zig").assert;
33
4// TODO issue #393
5pub const frexp = frexp_workaround;
6
47fn frexp_result(comptime T: type) -> type {
58 struct {
69 significand: T,
......@@ -10,7 +13,7 @@ fn frexp_result(comptime T: type) -> type {
1013pub const frexp32_result = frexp_result(f32);
1114pub const frexp64_result = frexp_result(f64);
1215
13pub fn frexp(x: var) -> frexp_result(@typeOf(x)) {
16pub fn frexp_workaround(x: var) -> frexp_result(@typeOf(x)) {
1417 const T = @typeOf(x);
1518 switch (T) {
1619 f32 => @inlineCall(frexp32, x),
......@@ -80,7 +83,7 @@ fn frexp64(x: f64) -> frexp64_result {
8083 result
8184}
8285
83test "frexp" {
86test "math.frexp" {
8487 const a = frexp(f32(1.3));
8588 const b = frexp32(1.3);
8689 assert(a.significand == b.significand and a.exponent == b.exponent);
......@@ -90,7 +93,7 @@ test "frexp" {
9093 assert(c.significand == d.significand and c.exponent == d.exponent);
9194}
9295
93test "frexp32" {
96test "math.frexp32" {
9497 const epsilon = 0.000001;
9598 var r: frexp32_result = undefined;
9699
......@@ -101,7 +104,7 @@ test "frexp32" {
101104 assert(math.approxEq(f32, r.significand, 0.609558, epsilon) and r.exponent == 7);
102105}
103106
104test "frexp64" {
107test "math.frexp64" {
105108 const epsilon = 0.000001;
106109 var r: frexp64_result = undefined;
107110
std/math/hypot.zig+7-4
......@@ -1,7 +1,10 @@
11const math = @import("index.zig");
22const assert = @import("../debug.zig").assert;
33
4pub fn hypot(comptime T: type, x: T, y: T) -> T {
4// TODO issue #393
5pub const hypot = hypot_workaround;
6
7pub fn hypot_workaround(comptime T: type, x: T, y: T) -> T {
58 switch (T) {
69 f32 => @inlineCall(hypot32, x, y),
710 f64 => @inlineCall(hypot64, x, y),
......@@ -105,12 +108,12 @@ fn hypot64(x: f64, y: f64) -> f64 {
105108 z * math.sqrt(ly + lx + hy + hx)
106109}
107110
108test "hypot" {
111test "math.hypot" {
109112 assert(hypot(f32, 0.0, -1.2) == hypot32(0.0, -1.2));
110113 assert(hypot(f64, 0.0, -1.2) == hypot64(0.0, -1.2));
111114}
112115
113test "hypot32" {
116test "math.hypot32" {
114117 const epsilon = 0.000001;
115118
116119 assert(math.approxEq(f32, hypot32(0.0, -1.2), 1.2, epsilon));
......@@ -122,7 +125,7 @@ test "hypot32" {
122125 assert(math.approxEq(f32, hypot32(123123.234375, 529428.707813), 543556.875, epsilon));
123126}
124127
125test "hypot64" {
128test "math.hypot64" {
126129 const epsilon = 0.000001;
127130
128131 assert(math.approxEq(f64, hypot64(0.0, -1.2), 1.2, epsilon));
std/math/ilogb.zig+7-4
......@@ -1,7 +1,10 @@
11const math = @import("index.zig");
22const assert = @import("../debug.zig").assert;
33
4pub fn ilogb(x: var) -> i32 {
4// TODO issue #393
5pub const ilogb = ilogb_workaround;
6
7pub fn ilogb_workaround(x: var) -> i32 {
58 const T = @typeOf(x);
69 switch (T) {
710 f32 => @inlineCall(ilogb32, x),
......@@ -76,12 +79,12 @@ fn ilogb64(x: f64) -> i32 {
7679 e - 0x3FF
7780}
7881
79test "ilogb" {
82test "math.ilogb" {
8083 assert(ilogb(f32(0.2)) == ilogb32(0.2));
8184 assert(ilogb(f64(0.2)) == ilogb64(0.2));
8285}
8386
84test "ilogb32" {
87test "math.ilogb32" {
8588 assert(ilogb32(0.0) == fp_ilogb0);
8689 assert(ilogb32(0.5) == -1);
8790 assert(ilogb32(0.8923) == -1);
......@@ -90,7 +93,7 @@ test "ilogb32" {
9093 assert(ilogb32(2398.23) == 11);
9194}
9295
93test "ilogb64" {
96test "math.ilogb64" {
9497 assert(ilogb64(0.0) == fp_ilogb0);
9598 assert(ilogb64(0.5) == -1);
9699 assert(ilogb64(0.8923) == -1);
std/math/index.zig-2
......@@ -98,7 +98,6 @@ pub const round = @import("round.zig").round;
9898pub const frexp = @import("frexp.zig").frexp;
9999pub const frexp32_result = @import("frexp.zig").frexp32_result;
100100pub const frexp64_result = @import("frexp.zig").frexp64_result;
101pub const fmod = @import("fmod.zig").fmod;
102101pub const modf = @import("modf.zig").modf;
103102pub const modf32_result = @import("modf.zig").modf32_result;
104103pub const modf64_result = @import("modf.zig").modf64_result;
......@@ -147,7 +146,6 @@ test "math" {
147146 _ = @import("trunc.zig");
148147 _ = @import("round.zig");
149148 _ = @import("frexp.zig");
150 _ = @import("fmod.zig");
151149 _ = @import("modf.zig");
152150 _ = @import("copysign.zig");
153151 _ = @import("isfinite.zig");
std/math/isfinite.zig+1-1
......@@ -18,7 +18,7 @@ pub fn isFinite(x: var) -> bool {
1818 }
1919}
2020
21test "isFinite" {
21test "math.isFinite" {
2222 assert(isFinite(f32(0.0)));
2323 assert(isFinite(f32(-0.0)));
2424 assert(isFinite(f64(0.0)));
std/math/isinf.zig+3-3
......@@ -48,7 +48,7 @@ pub fn isNegativeInf(x: var) -> bool {
4848 }
4949}
5050
51test "isInf" {
51test "math.isInf" {
5252 assert(!isInf(f32(0.0)));
5353 assert(!isInf(f32(-0.0)));
5454 assert(!isInf(f64(0.0)));
......@@ -59,7 +59,7 @@ test "isInf" {
5959 assert(isInf(-math.inf(f64)));
6060}
6161
62test "isPositiveInf" {
62test "math.isPositiveInf" {
6363 assert(!isPositiveInf(f32(0.0)));
6464 assert(!isPositiveInf(f32(-0.0)));
6565 assert(!isPositiveInf(f64(0.0)));
......@@ -70,7 +70,7 @@ test "isPositiveInf" {
7070 assert(!isPositiveInf(-math.inf(f64)));
7171}
7272
73test "isNegativeInf" {
73test "math.isNegativeInf" {
7474 assert(!isNegativeInf(f32(0.0)));
7575 assert(!isNegativeInf(f32(-0.0)));
7676 assert(!isNegativeInf(f64(0.0)));
std/math/isnan.zig+1-1
......@@ -18,7 +18,7 @@ pub fn isNan(x: var) -> bool {
1818 }
1919}
2020
21test "isNan" {
21test "math.isNan" {
2222 assert(isNan(math.nan(f32)));
2323 assert(isNan(math.nan(f64)));
2424 assert(!isNan(f32(1.0)));
std/math/isnormal.zig+1-1
......@@ -18,7 +18,7 @@ pub fn isNormal(x: var) -> bool {
1818 }
1919}
2020
21test "isNormal" {
21test "math.isNormal" {
2222 assert(!isNormal(math.nan(f32)));
2323 assert(!isNormal(math.nan(f64)));
2424 assert(isNormal(f32(1.0)));
std/math/ln.zig+3-1
......@@ -1,7 +1,9 @@
11const math = @import("index.zig");
22const assert = @import("../debug.zig").assert;
33
4pub fn ln(x: var) -> @typeOf(x) {
4pub const ln = ln_workaround;
5
6pub fn ln_workaround(x: var) -> @typeOf(x) {
57 const T = @typeOf(x);
68 switch (T) {
79 f32 => @inlineCall(lnf, x),
std/math/log.zig+17-25
......@@ -2,7 +2,10 @@ const math = @import("index.zig");
22const builtin = @import("builtin");
33const assert = @import("../debug.zig").assert;
44
5pub fn log(comptime base: usize, x: var) -> @typeOf(x) {
5// TODO issue #393
6pub const log = log_workaround;
7
8pub fn log_workaround(comptime base: usize, x: var) -> @typeOf(x) {
69 const T = @typeOf(x);
710 switch (@typeId(T)) {
811 builtin.TypeId.Int => {
......@@ -13,41 +16,30 @@ pub fn log(comptime base: usize, x: var) -> @typeOf(x) {
1316 }
1417 },
1518
16 builtin.TypeId.Float => {
17 return logf(base, x);
18 },
19
20 else => {
21 @compileError("log expects integer or float, found '" ++ @typeName(T) ++ "'");
22 },
23 }
24}
25
26fn logf(comptime base: usize, x: var) -> @typeOf(x) {
27 const T = @typeOf(x);
28 switch (T) {
29 f32 => {
30 switch (base) {
19 builtin.TypeId.Float => switch (T) {
20 f32 => switch (base) {
3121 2 => return math.log2(x),
3222 10 => return math.log10(x),
3323 else => return f32(math.ln(f64(x)) / math.ln(f64(base))),
34 }
35 },
24 },
3625
37 f64 => {
38 switch (base) {
26 f64 => switch (base) {
3927 2 => return math.log2(x),
4028 10 => return math.log10(x),
4129 // NOTE: This likely is computed with reduced accuracy.
4230 else => return math.ln(x) / math.ln(f64(base)),
43 }
31 },
32
33 else => @compileError("log not implemented for " ++ @typeName(T)),
4434 },
4535
46 else => @compileError("log not implemented for " ++ @typeName(T)),
36 else => {
37 @compileError("log expects integer or float, found '" ++ @typeName(T) ++ "'");
38 },
4739 }
4840}
4941
50test "log_integer" {
42test "math.log integer" {
5143 assert(log(2, u8(0x1)) == 0);
5244 assert(log(2, u8(0x2)) == 1);
5345 assert(log(2, i16(0x72)) == 6);
......@@ -55,7 +47,7 @@ test "log_integer" {
5547 assert(log(2, u64(0x7FF0123456789ABC)) == 62);
5648}
5749
58test "log_float" {
50test "math.log float" {
5951 const epsilon = 0.000001;
6052
6153 assert(math.approxEq(f32, log(6, f32(0.23947)), -0.797723, epsilon));
......@@ -63,7 +55,7 @@ test "log_float" {
6355 assert(math.approxEq(f64, log(123897, f64(12389216414)), 1.981724596, epsilon));
6456}
6557
66test "log_float_special" {
58test "math.log float_special" {
6759 assert(log(2, f32(0.2301974)) == math.log2(f32(0.2301974)));
6860 assert(log(10, f32(0.2301974)) == math.log10(f32(0.2301974)));
6961
std/math/log10.zig+25-22
......@@ -1,16 +1,19 @@
11const math = @import("index.zig");
22const assert = @import("../debug.zig").assert;
33
4pub fn log10(x: var) -> @typeOf(x) {
4// TODO issue #393
5pub const log10 = log10_workaround;
6
7pub fn log10_workaround(x: var) -> @typeOf(x) {
58 const T = @typeOf(x);
69 switch (T) {
7 f32 => @inlineCall(log10f, x),
8 f64 => @inlineCall(log10d, x),
10 f32 => @inlineCall(log10_32, x),
11 f64 => @inlineCall(log10_64, x),
912 else => @compileError("log10 not implemented for " ++ @typeName(T)),
1013 }
1114}
1215
13fn log10f(x_: f32) -> f32 {
16fn log10_32(x_: f32) -> f32 {
1417 const ivln10hi: f32 = 4.3432617188e-01;
1518 const ivln10lo: f32 = -3.1689971365e-05;
1619 const log10_2hi: f32 = 3.0102920532e-01;
......@@ -70,7 +73,7 @@ fn log10f(x_: f32) -> f32 {
7073 dk * log10_2lo + (lo + hi) * ivln10lo + lo * ivln10hi + hi * ivln10hi + dk * log10_2hi
7174}
7275
73fn log10d(x_: f64) -> f64 {
76fn log10_64(x_: f64) -> f64 {
7477 const ivln10hi: f64 = 4.34294481878168880939e-01;
7578 const ivln10lo: f64 = 2.50829467116452752298e-11;
7679 const log10_2hi: f64 = 3.01029995663611771306e-01;
......@@ -147,29 +150,29 @@ fn log10d(x_: f64) -> f64 {
147150 val_lo + val_hi
148151}
149152
150test "log10" {
151 assert(log10(f32(0.2)) == log10f(0.2));
152 assert(log10(f64(0.2)) == log10d(0.2));
153test "math.log10" {
154 assert(log10(f32(0.2)) == log10_32(0.2));
155 assert(log10(f64(0.2)) == log10_64(0.2));
153156}
154157
155test "log10f" {
158test "math.log10_32" {
156159 const epsilon = 0.000001;
157160
158 assert(math.approxEq(f32, log10f(0.2), -0.698970, epsilon));
159 assert(math.approxEq(f32, log10f(0.8923), -0.049489, epsilon));
160 assert(math.approxEq(f32, log10f(1.5), 0.176091, epsilon));
161 assert(math.approxEq(f32, log10f(37.45), 1.573452, epsilon));
162 assert(math.approxEq(f32, log10f(89.123), 1.94999, epsilon));
163 assert(math.approxEq(f32, log10f(123123.234375), 5.09034, epsilon));
161 assert(math.approxEq(f32, log10_32(0.2), -0.698970, epsilon));
162 assert(math.approxEq(f32, log10_32(0.8923), -0.049489, epsilon));
163 assert(math.approxEq(f32, log10_32(1.5), 0.176091, epsilon));
164 assert(math.approxEq(f32, log10_32(37.45), 1.573452, epsilon));
165 assert(math.approxEq(f32, log10_32(89.123), 1.94999, epsilon));
166 assert(math.approxEq(f32, log10_32(123123.234375), 5.09034, epsilon));
164167}
165168
166test "log10d" {
169test "math.log10_64" {
167170 const epsilon = 0.000001;
168171
169 assert(math.approxEq(f64, log10d(0.2), -0.698970, epsilon));
170 assert(math.approxEq(f64, log10d(0.8923), -0.049489, epsilon));
171 assert(math.approxEq(f64, log10d(1.5), 0.176091, epsilon));
172 assert(math.approxEq(f64, log10d(37.45), 1.573452, epsilon));
173 assert(math.approxEq(f64, log10d(89.123), 1.94999, epsilon));
174 assert(math.approxEq(f64, log10d(123123.234375), 5.09034, epsilon));
172 assert(math.approxEq(f64, log10_64(0.2), -0.698970, epsilon));
173 assert(math.approxEq(f64, log10_64(0.8923), -0.049489, epsilon));
174 assert(math.approxEq(f64, log10_64(1.5), 0.176091, epsilon));
175 assert(math.approxEq(f64, log10_64(37.45), 1.573452, epsilon));
176 assert(math.approxEq(f64, log10_64(89.123), 1.94999, epsilon));
177 assert(math.approxEq(f64, log10_64(123123.234375), 5.09034, epsilon));
175178}
std/math/log1p.zig+27-24
......@@ -1,16 +1,19 @@
11const math = @import("index.zig");
22const assert = @import("../debug.zig").assert;
33
4pub fn log1p(x: var) -> @typeOf(x) {
4// TODO issue #393
5pub const log1p = log1p_workaround;
6
7pub fn log1p_workaround(x: var) -> @typeOf(x) {
58 const T = @typeOf(x);
69 switch (T) {
7 f32 => @inlineCall(log1pf, x),
8 f64 => @inlineCall(log1pd, x),
10 f32 => @inlineCall(log1p_32, x),
11 f64 => @inlineCall(log1p_64, x),
912 else => @compileError("log1p not implemented for " ++ @typeName(T)),
1013 }
1114}
1215
13fn log1pf(x: f32) -> f32 {
16fn log1p_32(x: f32) -> f32 {
1417 const ln2_hi = 6.9313812256e-01;
1518 const ln2_lo = 9.0580006145e-06;
1619 const Lg1: f32 = 0xaaaaaa.0p-24;
......@@ -86,7 +89,7 @@ fn log1pf(x: f32) -> f32 {
8689 s * (hfsq + R) + (dk * ln2_lo + c) - hfsq + f + dk * ln2_hi
8790}
8891
89fn log1pd(x: f64) -> f64 {
92fn log1p_64(x: f64) -> f64 {
9093 const ln2_hi: f64 = 6.93147180369123816490e-01;
9194 const ln2_lo: f64 = 1.90821492927058770002e-10;
9295 const Lg1: f64 = 6.666666666666735130e-01;
......@@ -167,31 +170,31 @@ fn log1pd(x: f64) -> f64 {
167170 s * (hfsq + R) + (dk * ln2_lo + c) - hfsq + f + dk * ln2_hi
168171}
169172
170test "log1p" {
171 assert(log1p(f32(0.0)) == log1pf(0.0));
172 assert(log1p(f64(0.0)) == log1pd(0.0));
173test "math.log1p" {
174 assert(log1p(f32(0.0)) == log1p_32(0.0));
175 assert(log1p(f64(0.0)) == log1p_64(0.0));
173176}
174177
175test "log1pf" {
178test "math.log1p_32" {
176179 const epsilon = 0.000001;
177180
178 assert(math.approxEq(f32, log1pf(0.0), 0.0, epsilon));
179 assert(math.approxEq(f32, log1pf(0.2), 0.182322, epsilon));
180 assert(math.approxEq(f32, log1pf(0.8923), 0.637793, epsilon));
181 assert(math.approxEq(f32, log1pf(1.5), 0.916291, epsilon));
182 assert(math.approxEq(f32, log1pf(37.45), 3.649359, epsilon));
183 assert(math.approxEq(f32, log1pf(89.123), 4.501175, epsilon));
184 assert(math.approxEq(f32, log1pf(123123.234375), 11.720949, epsilon));
181 assert(math.approxEq(f32, log1p_32(0.0), 0.0, epsilon));
182 assert(math.approxEq(f32, log1p_32(0.2), 0.182322, epsilon));
183 assert(math.approxEq(f32, log1p_32(0.8923), 0.637793, epsilon));
184 assert(math.approxEq(f32, log1p_32(1.5), 0.916291, epsilon));
185 assert(math.approxEq(f32, log1p_32(37.45), 3.649359, epsilon));
186 assert(math.approxEq(f32, log1p_32(89.123), 4.501175, epsilon));
187 assert(math.approxEq(f32, log1p_32(123123.234375), 11.720949, epsilon));
185188}
186189
187test "log1pd" {
190test "math.log1p_64" {
188191 const epsilon = 0.000001;
189192
190 assert(math.approxEq(f64, log1pd(0.0), 0.0, epsilon));
191 assert(math.approxEq(f64, log1pd(0.2), 0.182322, epsilon));
192 assert(math.approxEq(f64, log1pd(0.8923), 0.637793, epsilon));
193 assert(math.approxEq(f64, log1pd(1.5), 0.916291, epsilon));
194 assert(math.approxEq(f64, log1pd(37.45), 3.649359, epsilon));
195 assert(math.approxEq(f64, log1pd(89.123), 4.501175, epsilon));
196 assert(math.approxEq(f64, log1pd(123123.234375), 11.720949, epsilon));
193 assert(math.approxEq(f64, log1p_64(0.0), 0.0, epsilon));
194 assert(math.approxEq(f64, log1p_64(0.2), 0.182322, epsilon));
195 assert(math.approxEq(f64, log1p_64(0.8923), 0.637793, epsilon));
196 assert(math.approxEq(f64, log1p_64(1.5), 0.916291, epsilon));
197 assert(math.approxEq(f64, log1p_64(37.45), 3.649359, epsilon));
198 assert(math.approxEq(f64, log1p_64(89.123), 4.501175, epsilon));
199 assert(math.approxEq(f64, log1p_64(123123.234375), 11.720949, epsilon));
197200}
std/math/log2.zig+23-20
......@@ -1,16 +1,19 @@
11const math = @import("index.zig");
22const assert = @import("../debug.zig").assert;
33
4pub fn log2(x: var) -> @typeOf(x) {
4// TODO issue #393
5pub const log2 = log2_workaround;
6
7pub fn log2_workaround(x: var) -> @typeOf(x) {
58 const T = @typeOf(x);
69 switch (T) {
7 f32 => @inlineCall(log2f, x),
8 f64 => @inlineCall(log2d, x),
10 f32 => @inlineCall(log2_32, x),
11 f64 => @inlineCall(log2_64, x),
912 else => @compileError("log2 not implemented for " ++ @typeName(T)),
1013 }
1114}
1215
13fn log2f(x_: f32) -> f32 {
16fn log2_32(x_: f32) -> f32 {
1417 const ivln2hi: f32 = 1.4428710938e+00;
1518 const ivln2lo: f32 = -1.7605285393e-04;
1619 const Lg1: f32 = 0xaaaaaa.0p-24;
......@@ -66,7 +69,7 @@ fn log2f(x_: f32) -> f32 {
6669 (lo + hi) * ivln2lo + lo * ivln2hi + hi * ivln2hi + f32(k)
6770}
6871
69fn log2d(x_: f64) -> f64 {
72fn log2_64(x_: f64) -> f64 {
7073 const ivln2hi: f64 = 1.44269504072144627571e+00;
7174 const ivln2lo: f64 = 1.67517131648865118353e-10;
7275 const Lg1: f64 = 6.666666666666735130e-01;
......@@ -139,27 +142,27 @@ fn log2d(x_: f64) -> f64 {
139142 val_lo + val_hi
140143}
141144
142test "log2" {
143 assert(log2(f32(0.2)) == log2f(0.2));
144 assert(log2(f64(0.2)) == log2d(0.2));
145test "math.log2" {
146 assert(log2(f32(0.2)) == log2_32(0.2));
147 assert(log2(f64(0.2)) == log2_64(0.2));
145148}
146149
147test "log2f" {
150test "math.log2_32" {
148151 const epsilon = 0.000001;
149152
150 assert(math.approxEq(f32, log2f(0.2), -2.321928, epsilon));
151 assert(math.approxEq(f32, log2f(0.8923), -0.164399, epsilon));
152 assert(math.approxEq(f32, log2f(1.5), 0.584962, epsilon));
153 assert(math.approxEq(f32, log2f(37.45), 5.226894, epsilon));
154 assert(math.approxEq(f32, log2f(123123.234375), 16.909744, epsilon));
153 assert(math.approxEq(f32, log2_32(0.2), -2.321928, epsilon));
154 assert(math.approxEq(f32, log2_32(0.8923), -0.164399, epsilon));
155 assert(math.approxEq(f32, log2_32(1.5), 0.584962, epsilon));
156 assert(math.approxEq(f32, log2_32(37.45), 5.226894, epsilon));
157 assert(math.approxEq(f32, log2_32(123123.234375), 16.909744, epsilon));
155158}
156159
157test "log2d" {
160test "math.log2_64" {
158161 const epsilon = 0.000001;
159162
160 assert(math.approxEq(f64, log2d(0.2), -2.321928, epsilon));
161 assert(math.approxEq(f64, log2d(0.8923), -0.164399, epsilon));
162 assert(math.approxEq(f64, log2d(1.5), 0.584962, epsilon));
163 assert(math.approxEq(f64, log2d(37.45), 5.226894, epsilon));
164 assert(math.approxEq(f64, log2d(123123.234375), 16.909744, epsilon));
163 assert(math.approxEq(f64, log2_64(0.2), -2.321928, epsilon));
164 assert(math.approxEq(f64, log2_64(0.8923), -0.164399, epsilon));
165 assert(math.approxEq(f64, log2_64(1.5), 0.584962, epsilon));
166 assert(math.approxEq(f64, log2_64(37.45), 5.226894, epsilon));
167 assert(math.approxEq(f64, log2_64(123123.234375), 16.909744, epsilon));
165168}
std/math/modf.zig+7-4
......@@ -1,6 +1,9 @@
11const math = @import("index.zig");
22const assert = @import("../debug.zig").assert;
33
4// TODO issue #393
5pub const modf = modf_workaround;
6
47fn modf_result(comptime T: type) -> type {
58 struct {
69 fpart: T,
......@@ -10,7 +13,7 @@ fn modf_result(comptime T: type) -> type {
1013pub const modf32_result = modf_result(f32);
1114pub const modf64_result = modf_result(f64);
1215
13pub fn modf(x: var) -> modf_result(@typeOf(x)) {
16pub fn modf_workaround(x: var) -> modf_result(@typeOf(x)) {
1417 const T = @typeOf(x);
1518 switch (T) {
1619 f32 => @inlineCall(modf32, x),
......@@ -95,7 +98,7 @@ fn modf64(x: f64) -> modf64_result {
9598 result
9699}
97100
98test "modf" {
101test "math.modf" {
99102 const a = modf(f32(1.0));
100103 const b = modf32(1.0);
101104 // NOTE: No struct comparison on generic return type function? non-named, makes sense, but still.
......@@ -106,7 +109,7 @@ test "modf" {
106109 assert(a.ipart == b.ipart and a.fpart == b.fpart);
107110}
108111
109test "modf32" {
112test "math.modf32" {
110113 const epsilon = 0.000001;
111114 var r: modf32_result = undefined;
112115
......@@ -131,7 +134,7 @@ test "modf32" {
131134 assert(math.approxEq(f32, r.fpart, 0.340820, epsilon));
132135}
133136
134test "modf64" {
137test "math.modf64" {
135138 const epsilon = 0.000001;
136139 var r: modf64_result = undefined;
137140
std/math/nan.zig+3-1
......@@ -1,6 +1,8 @@
11const math = @import("index.zig");
22
3pub fn nan(comptime T: type) -> T {
3pub const nan = nan_workaround;
4
5pub fn nan_workaround(comptime T: type) -> T {
46 switch (T) {
57 f32 => @bitCast(f32, math.nan_u32),
68 f64 => @bitCast(f64, math.nan_u64),
std/math/oindex.zig deleted-274
......@@ -1,274 +0,0 @@
1const assert = @import("../debug.zig").assert;
2const builtin = @import("builtin");
3
4pub const frexp = @import("frexp.zig").frexp;
5
6pub const Cmp = enum {
7 Less,
8 Equal,
9 Greater,
10};
11
12pub fn min(x: var, y: var) -> @typeOf(x + y) {
13 if (x < y) x else y
14}
15
16test "math.min" {
17 assert(min(i32(-1), i32(2)) == -1);
18}
19
20pub fn max(x: var, y: var) -> @typeOf(x + y) {
21 if (x > y) x else y
22}
23
24test "math.max" {
25 assert(max(i32(-1), i32(2)) == 2);
26}
27
28error Overflow;
29pub fn mul(comptime T: type, a: T, b: T) -> %T {
30 var answer: T = undefined;
31 if (@mulWithOverflow(T, a, b, &answer)) error.Overflow else answer
32}
33
34error Overflow;
35pub fn add(comptime T: type, a: T, b: T) -> %T {
36 var answer: T = undefined;
37 if (@addWithOverflow(T, a, b, &answer)) error.Overflow else answer
38}
39
40error Overflow;
41pub fn sub(comptime T: type, a: T, b: T) -> %T {
42 var answer: T = undefined;
43 if (@subWithOverflow(T, a, b, &answer)) error.Overflow else answer
44}
45
46pub fn negate(x: var) -> %@typeOf(x) {
47 return sub(@typeOf(x), 0, x);
48}
49
50error Overflow;
51pub fn shl(comptime T: type, a: T, b: T) -> %T {
52 var answer: T = undefined;
53 if (@shlWithOverflow(T, a, b, &answer)) error.Overflow else answer
54}
55
56test "math overflow functions" {
57 testOverflow();
58 comptime testOverflow();
59}
60
61fn testOverflow() {
62 assert(%%mul(i32, 3, 4) == 12);
63 assert(%%add(i32, 3, 4) == 7);
64 assert(%%sub(i32, 3, 4) == -1);
65 assert(%%shl(i32, 0b11, 4) == 0b110000);
66}
67
68
69error Overflow;
70pub fn absInt(x: var) -> %@typeOf(x) {
71 const T = @typeOf(x);
72 comptime assert(@typeId(T) == builtin.TypeId.Int); // must pass an integer to absInt
73 comptime assert(T.is_signed); // must pass a signed integer to absInt
74 if (x == @minValue(@typeOf(x)))
75 return error.Overflow;
76 {
77 @setDebugSafety(this, false);
78 return if (x < 0) -x else x;
79 }
80}
81
82test "math.absInt" {
83 testAbsInt();
84 comptime testAbsInt();
85}
86fn testAbsInt() {
87 assert(%%absInt(i32(-10)) == 10);
88 assert(%%absInt(i32(10)) == 10);
89}
90
91pub const absFloat = @import("fabs.zig").fabs;
92
93error DivisionByZero;
94error Overflow;
95pub fn divTrunc(comptime T: type, numerator: T, denominator: T) -> %T {
96 @setDebugSafety(this, false);
97 if (denominator == 0)
98 return error.DivisionByZero;
99 if (@typeId(T) == builtin.TypeId.Int and T.is_signed and numerator == @minValue(T) and denominator == -1)
100 return error.Overflow;
101 return @divTrunc(numerator, denominator);
102}
103
104test "math.divTrunc" {
105 testDivTrunc();
106 comptime testDivTrunc();
107}
108fn testDivTrunc() {
109 assert(%%divTrunc(i32, 5, 3) == 1);
110 assert(%%divTrunc(i32, -5, 3) == -1);
111 if (divTrunc(i8, -5, 0)) |_| unreachable else |err| assert(err == error.DivisionByZero);
112 if (divTrunc(i8, -128, -1)) |_| unreachable else |err| assert(err == error.Overflow);
113
114 assert(%%divTrunc(f32, 5.0, 3.0) == 1.0);
115 assert(%%divTrunc(f32, -5.0, 3.0) == -1.0);
116}
117
118error DivisionByZero;
119error Overflow;
120pub fn divFloor(comptime T: type, numerator: T, denominator: T) -> %T {
121 @setDebugSafety(this, false);
122 if (denominator == 0)
123 return error.DivisionByZero;
124 if (@typeId(T) == builtin.TypeId.Int and T.is_signed and numerator == @minValue(T) and denominator == -1)
125 return error.Overflow;
126 return @divFloor(numerator, denominator);
127}
128
129test "math.divFloor" {
130 testDivFloor();
131 comptime testDivFloor();
132}
133fn testDivFloor() {
134 assert(%%divFloor(i32, 5, 3) == 1);
135 assert(%%divFloor(i32, -5, 3) == -2);
136 if (divFloor(i8, -5, 0)) |_| unreachable else |err| assert(err == error.DivisionByZero);
137 if (divFloor(i8, -128, -1)) |_| unreachable else |err| assert(err == error.Overflow);
138
139 assert(%%divFloor(f32, 5.0, 3.0) == 1.0);
140 assert(%%divFloor(f32, -5.0, 3.0) == -2.0);
141}
142
143error DivisionByZero;
144error Overflow;
145error UnexpectedRemainder;
146pub fn divExact(comptime T: type, numerator: T, denominator: T) -> %T {
147 @setDebugSafety(this, false);
148 if (denominator == 0)
149 return error.DivisionByZero;
150 if (@typeId(T) == builtin.TypeId.Int and T.is_signed and numerator == @minValue(T) and denominator == -1)
151 return error.Overflow;
152 const result = @divTrunc(numerator, denominator);
153 if (result * denominator != numerator)
154 return error.UnexpectedRemainder;
155 return result;
156}
157
158test "math.divExact" {
159 testDivExact();
160 comptime testDivExact();
161}
162fn testDivExact() {
163 assert(%%divExact(i32, 10, 5) == 2);
164 assert(%%divExact(i32, -10, 5) == -2);
165 if (divExact(i8, -5, 0)) |_| unreachable else |err| assert(err == error.DivisionByZero);
166 if (divExact(i8, -128, -1)) |_| unreachable else |err| assert(err == error.Overflow);
167 if (divExact(i32, 5, 2)) |_| unreachable else |err| assert(err == error.UnexpectedRemainder);
168
169 assert(%%divExact(f32, 10.0, 5.0) == 2.0);
170 assert(%%divExact(f32, -10.0, 5.0) == -2.0);
171 if (divExact(f32, 5.0, 2.0)) |_| unreachable else |err| assert(err == error.UnexpectedRemainder);
172}
173
174error DivisionByZero;
175error NegativeDenominator;
176pub fn mod(comptime T: type, numerator: T, denominator: T) -> %T {
177 @setDebugSafety(this, false);
178 if (denominator == 0)
179 return error.DivisionByZero;
180 if (denominator < 0)
181 return error.NegativeDenominator;
182 return @mod(numerator, denominator);
183}
184
185test "math.mod" {
186 testMod();
187 comptime testMod();
188}
189fn testMod() {
190 assert(%%mod(i32, -5, 3) == 1);
191 assert(%%mod(i32, 5, 3) == 2);
192 if (mod(i32, 10, -1)) |_| unreachable else |err| assert(err == error.NegativeDenominator);
193 if (mod(i32, 10, 0)) |_| unreachable else |err| assert(err == error.DivisionByZero);
194
195 assert(%%mod(f32, -5, 3) == 1);
196 assert(%%mod(f32, 5, 3) == 2);
197 if (mod(f32, 10, -1)) |_| unreachable else |err| assert(err == error.NegativeDenominator);
198 if (mod(f32, 10, 0)) |_| unreachable else |err| assert(err == error.DivisionByZero);
199}
200
201error DivisionByZero;
202error NegativeDenominator;
203pub fn rem(comptime T: type, numerator: T, denominator: T) -> %T {
204 @setDebugSafety(this, false);
205 if (denominator == 0)
206 return error.DivisionByZero;
207 if (denominator < 0)
208 return error.NegativeDenominator;
209 return @rem(numerator, denominator);
210}
211
212test "math.rem" {
213 testRem();
214 comptime testRem();
215}
216fn testRem() {
217 assert(%%rem(i32, -5, 3) == -2);
218 assert(%%rem(i32, 5, 3) == 2);
219 if (rem(i32, 10, -1)) |_| unreachable else |err| assert(err == error.NegativeDenominator);
220 if (rem(i32, 10, 0)) |_| unreachable else |err| assert(err == error.DivisionByZero);
221
222 assert(%%rem(f32, -5, 3) == -2);
223 assert(%%rem(f32, 5, 3) == 2);
224 if (rem(f32, 10, -1)) |_| unreachable else |err| assert(err == error.NegativeDenominator);
225 if (rem(f32, 10, 0)) |_| unreachable else |err| assert(err == error.DivisionByZero);
226}
227
228/// Returns the absolute value of the integer parameter.
229/// Result is an unsigned integer.
230pub fn absCast(x: var) -> @IntType(false, @typeOf(x).bit_count) {
231 const uint = @IntType(false, @typeOf(x).bit_count);
232 if (x >= 0)
233 return uint(x);
234
235 return uint(-(x + 1)) + 1;
236}
237
238test "math.absCast" {
239 assert(absCast(i32(-999)) == 999);
240 assert(@typeOf(absCast(i32(-999))) == u32);
241
242 assert(absCast(i32(999)) == 999);
243 assert(@typeOf(absCast(i32(999))) == u32);
244
245 assert(absCast(i32(@minValue(i32))) == -@minValue(i32));
246 assert(@typeOf(absCast(i32(@minValue(i32)))) == u32);
247}
248
249/// Returns the negation of the integer parameter.
250/// Result is a signed integer.
251error Overflow;
252pub fn negateCast(x: var) -> %@IntType(true, @typeOf(x).bit_count) {
253 if (@typeOf(x).is_signed)
254 return negate(x);
255
256 const int = @IntType(true, @typeOf(x).bit_count);
257 if (x > -@minValue(int))
258 return error.Overflow;
259
260 if (x == -@minValue(int))
261 return @minValue(int);
262
263 return -int(x);
264}
265
266test "math.negateCast" {
267 assert(%%negateCast(u32(999)) == -999);
268 assert(@typeOf(%%negateCast(u32(999))) == i32);
269
270 assert(%%negateCast(u32(-@minValue(i32))) == @minValue(i32));
271 assert(@typeOf(%%negateCast(u32(-@minValue(i32)))) == i32);
272
273 if (negateCast(u32(@maxValue(i32) + 10))) |_| unreachable else |err| assert(err == error.Overflow);
274}
std/math/pow.zig+5-4
......@@ -1,8 +1,11 @@
11const math = @import("index.zig");
22const assert = @import("../debug.zig").assert;
33
4// TODO issue #393
5pub const pow = pow_workaround;
6
47// This implementation is taken from the go stlib, musl is a bit more complex.
5pub fn pow(comptime T: type, x: T, y: T) -> T {
8pub fn pow_workaround(comptime T: type, x: T, y: T) -> T {
69
710 @setFloatMode(this, @import("builtin").FloatMode.Strict);
811
......@@ -158,9 +161,7 @@ test "math.pow" {
158161 assert(math.approxEq(f32, pow(f32, 0.2, 3.3), 0.004936, epsilon));
159162 assert(math.approxEq(f32, pow(f32, 1.5, 3.3), 3.811546, epsilon));
160163 assert(math.approxEq(f32, pow(f32, 37.45, 3.3), 155736.703125, epsilon));
161
162 // TODO: Determine why aborting on release mode.
163 // assert(math.approxEq(f32, pow(f32, 89.123, 3.3), 2722489.5, epsilon));
164 assert(math.approxEq(f32, pow(f32, 89.123, 3.3), 2722489.5, epsilon));
164165
165166 // assert(math.approxEq(f32, pow(f64, 0.0, 3.3), 0.0, epsilon)); // TODO: Handle div zero
166167 assert(math.approxEq(f64, pow(f64, 0.8923, 3.3), 0.686572, epsilon));
std/math/round.zig+7-4
......@@ -2,7 +2,10 @@ const builtin = @import("builtin");
22const assert = @import("../debug.zig").assert;
33const math = @import("index.zig");
44
5pub fn round(x: var) -> @typeOf(x) {
5// TODO issue #393
6pub const round = round_workaround;
7
8pub fn round_workaround(x: var) -> @typeOf(x) {
69 const T = @typeOf(x);
710 switch (T) {
811 f32 => @inlineCall(round32, x),
......@@ -85,19 +88,19 @@ fn round64(x_: f64) -> f64 {
8588 }
8689}
8790
88test "round" {
91test "math.round" {
8992 assert(round(f32(1.3)) == round32(1.3));
9093 assert(round(f64(1.3)) == round64(1.3));
9194}
9295
93test "round32" {
96test "math.round32" {
9497 assert(round32(1.3) == 1.0);
9598 assert(round32(-1.3) == -1.0);
9699 assert(round32(0.2) == 0.0);
97100 assert(round32(1.8) == 2.0);
98101}
99102
100test "round64" {
103test "math.round64" {
101104 assert(round64(1.3) == 1.0);
102105 assert(round64(-1.3) == -1.0);
103106 assert(round64(0.2) == 0.0);
std/math/scalbn.zig+7-4
......@@ -1,7 +1,10 @@
11const math = @import("index.zig");
22const assert = @import("../debug.zig").assert;
33
4pub fn scalbn(x: var, n: i32) -> @typeOf(x) {
4// TODO issue #393
5pub const scalbn = scalbn_workaround;
6
7pub fn scalbn_workaround(x: var, n: i32) -> @typeOf(x) {
58 const T = @typeOf(x);
69 switch (T) {
710 f32 => @inlineCall(scalbn32, x, n),
......@@ -71,15 +74,15 @@ fn scalbn64(x: f64, n_: i32) -> f64 {
7174 y * @bitCast(f64, u)
7275}
7376
74test "scalbn" {
77test "math.scalbn" {
7578 assert(scalbn(f32(1.5), 4) == scalbn32(1.5, 4));
7679 assert(scalbn(f64(1.5), 4) == scalbn64(1.5, 4));
7780}
7881
79test "scalbn32" {
82test "math.scalbn32" {
8083 assert(scalbn32(1.5, 4) == 24.0);
8184}
8285
83test "scalbn64" {
86test "math.scalbn64" {
8487 assert(scalbn64(1.5, 4) == 24.0);
8588}
std/math/signbit.zig+7-4
......@@ -1,7 +1,10 @@
11const math = @import("index.zig");
22const assert = @import("../debug.zig").assert;
33
4pub fn signbit(x: var) -> bool {
4// TODO issue #393
5pub const signbit = signbit_workaround;
6
7pub fn signbit_workaround(x: var) -> bool {
58 const T = @typeOf(x);
69 switch (T) {
710 f32 => @inlineCall(signbit32, x),
......@@ -20,17 +23,17 @@ fn signbit64(x: f64) -> bool {
2023 bits >> 63 != 0
2124}
2225
23test "signbit" {
26test "math.signbit" {
2427 assert(signbit(f32(4.0)) == signbit32(4.0));
2528 assert(signbit(f64(4.0)) == signbit64(4.0));
2629}
2730
28test "signbit32" {
31test "math.signbit32" {
2932 assert(!signbit32(4.0));
3033 assert(signbit32(-3.0));
3134}
3235
33test "signbit64" {
36test "math.signbit64" {
3437 assert(!signbit64(4.0));
3538 assert(signbit64(-3.0));
3639}
std/math/sin.zig+7-4
......@@ -1,7 +1,10 @@
11const math = @import("index.zig");
22const assert = @import("../debug.zig").assert;
33
4pub fn sin(x: var) -> @typeOf(x) {
4// TODO issue #393
5pub const sin = sin_workaround;
6
7pub fn sin_workaround(x: var) -> @typeOf(x) {
58 const T = @typeOf(x);
69 switch (T) {
710 f32 => @inlineCall(sin32, x),
......@@ -135,12 +138,12 @@ fn sin64(x_: f64) -> f64 {
135138 }
136139}
137140
138test "sin" {
141test "math.sin" {
139142 assert(sin(f32(0.0)) == sin32(0.0));
140143 assert(sin(f64(0.0)) == sin64(0.0));
141144}
142145
143test "sin32" {
146test "math.sin32" {
144147 const epsilon = 0.000001;
145148
146149 assert(math.approxEq(f32, sin32(0.0), 0.0, epsilon));
......@@ -151,7 +154,7 @@ test "sin32" {
151154 assert(math.approxEq(f32, sin32(89.123), 0.916166, epsilon));
152155}
153156
154test "sin64" {
157test "math.sin64" {
155158 const epsilon = 0.000001;
156159
157160 assert(math.approxEq(f64, sin64(0.0), 0.0, epsilon));
std/math/sinh.zig+21-18
......@@ -2,11 +2,14 @@ const math = @import("index.zig");
22const assert = @import("../debug.zig").assert;
33const expo2 = @import("_expo2.zig").expo2;
44
5pub fn sinh(x: var) -> @typeOf(x) {
5// TODO issue #393
6pub const sinh = sinh_workaround;
7
8pub fn sinh_workaround(x: var) -> @typeOf(x) {
69 const T = @typeOf(x);
710 switch (T) {
8 f32 => @inlineCall(sinhf, x),
9 f64 => @inlineCall(sinhd, x),
11 f32 => @inlineCall(sinh32, x),
12 f64 => @inlineCall(sinh64, x),
1013 else => @compileError("sinh not implemented for " ++ @typeName(T)),
1114 }
1215}
......@@ -14,7 +17,7 @@ pub fn sinh(x: var) -> @typeOf(x) {
1417// sinh(x) = (exp(x) - 1 / exp(x)) / 2
1518// = (exp(x) - 1 + (exp(x) - 1) / exp(x)) / 2
1619// = x + x^3 / 6 + o(x^5)
17fn sinhf(x: f32) -> f32 {
20fn sinh32(x: f32) -> f32 {
1821 const u = @bitCast(u32, x);
1922 const ux = u & 0x7FFFFFFF;
2023 const ax = @bitCast(f32, ux);
......@@ -41,7 +44,7 @@ fn sinhf(x: f32) -> f32 {
4144 2 * h * expo2(ax)
4245}
4346
44fn sinhd(x: f64) -> f64 {
47fn sinh64(x: f64) -> f64 {
4548 const u = @bitCast(u64, x);
4649 const w = u32(u >> 32);
4750 const ax = @bitCast(f64, u & (@maxValue(u64) >> 1));
......@@ -69,25 +72,25 @@ fn sinhd(x: f64) -> f64 {
6972 2 * h * expo2(ax)
7073}
7174
72test "sinh" {
73 assert(sinh(f32(1.5)) == sinhf(1.5));
74 assert(sinh(f64(1.5)) == sinhd(1.5));
75test "math.sinh" {
76 assert(sinh(f32(1.5)) == sinh32(1.5));
77 assert(sinh(f64(1.5)) == sinh64(1.5));
7578}
7679
77test "sinhf" {
80test "math.sinh32" {
7881 const epsilon = 0.000001;
7982
80 assert(math.approxEq(f32, sinhf(0.0), 0.0, epsilon));
81 assert(math.approxEq(f32, sinhf(0.2), 0.201336, epsilon));
82 assert(math.approxEq(f32, sinhf(0.8923), 1.015512, epsilon));
83 assert(math.approxEq(f32, sinhf(1.5), 2.129279, epsilon));
83 assert(math.approxEq(f32, sinh32(0.0), 0.0, epsilon));
84 assert(math.approxEq(f32, sinh32(0.2), 0.201336, epsilon));
85 assert(math.approxEq(f32, sinh32(0.8923), 1.015512, epsilon));
86 assert(math.approxEq(f32, sinh32(1.5), 2.129279, epsilon));
8487}
8588
86test "sinhd" {
89test "math.sinh64" {
8790 const epsilon = 0.000001;
8891
89 assert(math.approxEq(f64, sinhd(0.0), 0.0, epsilon));
90 assert(math.approxEq(f64, sinhd(0.2), 0.201336, epsilon));
91 assert(math.approxEq(f64, sinhd(0.8923), 1.015512, epsilon));
92 assert(math.approxEq(f64, sinhd(1.5), 2.129279, epsilon));
92 assert(math.approxEq(f64, sinh64(0.0), 0.0, epsilon));
93 assert(math.approxEq(f64, sinh64(0.2), 0.201336, epsilon));
94 assert(math.approxEq(f64, sinh64(0.8923), 1.015512, epsilon));
95 assert(math.approxEq(f64, sinh64(1.5), 2.129279, epsilon));
9396}
std/math/sqrt.zig+7-4
......@@ -1,7 +1,10 @@
11const math = @import("index.zig");
22const assert = @import("../debug.zig").assert;
33
4pub fn sqrt(x: var) -> @typeOf(x) {
4// TODO issue #393
5pub const sqrt = sqrt_workaround;
6
7pub fn sqrt_workaround(x: var) -> @typeOf(x) {
58 const T = @typeOf(x);
69 switch (T) {
710 f32 => @inlineCall(sqrt32, x),
......@@ -219,12 +222,12 @@ fn sqrt64(x: f64) -> f64 {
219222 @bitCast(f64, uz)
220223}
221224
222test "sqrt" {
225test "math.sqrt" {
223226 assert(sqrt(f32(0.0)) == sqrt32(0.0));
224227 assert(sqrt(f64(0.0)) == sqrt64(0.0));
225228}
226229
227test "sqrt32" {
230test "math.sqrt32" {
228231 const epsilon = 0.000001;
229232
230233 assert(sqrt32(0.0) == 0.0);
......@@ -238,7 +241,7 @@ test "sqrt32" {
238241 assert(math.approxEq(f32, sqrt32(8942.230469), 94.563370, epsilon));
239242}
240243
241test "sqrt64" {
244test "math.sqrt64" {
242245 const epsilon = 0.000001;
243246
244247 assert(sqrt64(0.0) == 0.0);
std/math/tan.zig+6-4
......@@ -1,7 +1,9 @@
11const math = @import("index.zig");
22const assert = @import("../debug.zig").assert;
33
4pub fn tan(x: var) -> @typeOf(x) {
4pub const tan = tan_workaround;
5
6pub fn tan_workaround(x: var) -> @typeOf(x) {
57 const T = @typeOf(x);
68 switch (T) {
79 f32 => @inlineCall(tan32, x),
......@@ -122,12 +124,12 @@ fn tan64(x_: f64) -> f64 {
122124 r
123125}
124126
125test "tan" {
127test "math.tan" {
126128 assert(tan(f32(0.0)) == tan32(0.0));
127129 assert(tan(f64(0.0)) == tan64(0.0));
128130}
129131
130test "tan32" {
132test "math.tan32" {
131133 const epsilon = 0.000001;
132134
133135 assert(math.approxEq(f32, tan32(0.0), 0.0, epsilon));
......@@ -138,7 +140,7 @@ test "tan32" {
138140 assert(math.approxEq(f32, tan32(89.123), 2.285852, epsilon));
139141}
140142
141test "tan64" {
143test "math.tan64" {
142144 const epsilon = 0.000001;
143145
144146 assert(math.approxEq(f64, tan64(0.0), 0.0, epsilon));
std/math/tanh.zig+23-20
......@@ -2,11 +2,14 @@ const math = @import("index.zig");
22const assert = @import("../debug.zig").assert;
33const expo2 = @import("_expo2.zig").expo2;
44
5pub fn tanh(x: var) -> @typeOf(x) {
5// TODO issue #393
6pub const tanh = tanh_workaround;
7
8pub fn tanh_workaround(x: var) -> @typeOf(x) {
69 const T = @typeOf(x);
710 switch (T) {
8 f32 => @inlineCall(tanhf, x),
9 f64 => @inlineCall(tanhd, x),
11 f32 => @inlineCall(tanh32, x),
12 f64 => @inlineCall(tanh64, x),
1013 else => @compileError("tanh not implemented for " ++ @typeName(T)),
1114 }
1215}
......@@ -14,7 +17,7 @@ pub fn tanh(x: var) -> @typeOf(x) {
1417// tanh(x) = (exp(x) - exp(-x)) / (exp(x) + exp(-x))
1518// = (exp(2x) - 1) / (exp(2x) - 1 + 2)
1619// = (1 - exp(-2x)) / (exp(-2x) - 1 + 2)
17fn tanhf(x: f32) -> f32 {
20fn tanh32(x: f32) -> f32 {
1821 const u = @bitCast(u32, x);
1922 const ux = u & 0x7FFFFFFF;
2023 const ax = @bitCast(f32, ux);
......@@ -54,7 +57,7 @@ fn tanhf(x: f32) -> f32 {
5457 }
5558}
5659
57fn tanhd(x: f64) -> f64 {
60fn tanh64(x: f64) -> f64 {
5861 const u = @bitCast(u64, x);
5962 const w = u32(u >> 32);
6063 const ax = @bitCast(f64, u & (@maxValue(u64) >> 1));
......@@ -94,27 +97,27 @@ fn tanhd(x: f64) -> f64 {
9497 }
9598}
9699
97test "tanh" {
98 assert(tanh(f32(1.5)) == tanhf(1.5));
99 assert(tanh(f64(1.5)) == tanhd(1.5));
100test "math.tanh" {
101 assert(tanh(f32(1.5)) == tanh32(1.5));
102 assert(tanh(f64(1.5)) == tanh64(1.5));
100103}
101104
102test "tanhf" {
105test "math.tanh32" {
103106 const epsilon = 0.000001;
104107
105 assert(math.approxEq(f32, tanhf(0.0), 0.0, epsilon));
106 assert(math.approxEq(f32, tanhf(0.2), 0.197375, epsilon));
107 assert(math.approxEq(f32, tanhf(0.8923), 0.712528, epsilon));
108 assert(math.approxEq(f32, tanhf(1.5), 0.905148, epsilon));
109 assert(math.approxEq(f32, tanhf(37.45), 1.0, epsilon));
108 assert(math.approxEq(f32, tanh32(0.0), 0.0, epsilon));
109 assert(math.approxEq(f32, tanh32(0.2), 0.197375, epsilon));
110 assert(math.approxEq(f32, tanh32(0.8923), 0.712528, epsilon));
111 assert(math.approxEq(f32, tanh32(1.5), 0.905148, epsilon));
112 assert(math.approxEq(f32, tanh32(37.45), 1.0, epsilon));
110113}
111114
112test "tanhd" {
115test "math.tanh64" {
113116 const epsilon = 0.000001;
114117
115 assert(math.approxEq(f64, tanhd(0.0), 0.0, epsilon));
116 assert(math.approxEq(f64, tanhd(0.2), 0.197375, epsilon));
117 assert(math.approxEq(f64, tanhd(0.8923), 0.712528, epsilon));
118 assert(math.approxEq(f64, tanhd(1.5), 0.905148, epsilon));
119 assert(math.approxEq(f64, tanhd(37.45), 1.0, epsilon));
118 assert(math.approxEq(f64, tanh64(0.0), 0.0, epsilon));
119 assert(math.approxEq(f64, tanh64(0.2), 0.197375, epsilon));
120 assert(math.approxEq(f64, tanh64(0.8923), 0.712528, epsilon));
121 assert(math.approxEq(f64, tanh64(1.5), 0.905148, epsilon));
122 assert(math.approxEq(f64, tanh64(37.45), 1.0, epsilon));
120123}
std/math/trunc.zig+6-4
......@@ -1,7 +1,9 @@
11const math = @import("index.zig");
22const assert = @import("../debug.zig").assert;
33
4pub fn trunc(x: var) -> @typeOf(x) {
4pub const trunc = trunc_workaround;
5
6pub fn trunc_workaround(x: var) -> @typeOf(x) {
57 const T = @typeOf(x);
68 switch (T) {
79 f32 => @inlineCall(trunc32, x),
......@@ -52,18 +54,18 @@ fn trunc64(x: f64) -> f64 {
5254 }
5355}
5456
55test "trunc" {
57test "math.trunc" {
5658 assert(trunc(f32(1.3)) == trunc32(1.3));
5759 assert(trunc(f64(1.3)) == trunc64(1.3));
5860}
5961
60test "trunc32" {
62test "math.trunc32" {
6163 assert(trunc32(1.3) == 1.0);
6264 assert(trunc32(-1.3) == -1.0);
6365 assert(trunc32(0.2) == 0.0);
6466}
6567
66test "trunc64" {
68test "math.trunc64" {
6769 assert(trunc64(1.3) == 1.0);
6870 assert(trunc64(-1.3) == -1.0);
6971 assert(trunc64(0.2) == 0.0);