diff --git a/src/codegen.cpp b/src/codegen.cpp index 20c9793dc..e9a263a6f 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -438,6 +438,7 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) { } addLLVMFnAttr(fn_table_entry->llvm_value, "nounwind"); + addLLVMFnAttr(fn_table_entry->llvm_value, "nobuiltin"); if (g->build_mode == BuildModeDebug && fn_table_entry->fn_inline != FnInlineAlways) { ZigLLVMAddFunctionAttr(fn_table_entry->llvm_value, "no-frame-pointer-elim", "true"); ZigLLVMAddFunctionAttr(fn_table_entry->llvm_value, "no-frame-pointer-elim-non-leaf", nullptr); diff --git a/std/math/acos.zig b/std/math/acos.zig index c6661a272..27764b301 100644 --- a/std/math/acos.zig +++ b/std/math/acos.zig @@ -1,7 +1,10 @@ const math = @import("index.zig"); const assert = @import("../debug.zig").assert; -pub fn acos(x: var) -> @typeOf(x) { +pub const acos = acos_workaround; + +// TODO issue #393 +pub fn acos_workaround(x: var) -> @typeOf(x) { const T = @typeOf(x); switch (T) { f32 => @inlineCall(acos32, x), @@ -137,12 +140,12 @@ fn acos64(x: f64) -> f64 { 2 * (df + w) } -test "acos" { - assert(acos(f32(0.0)) == acos32(0.0)); - assert(acos(f64(0.0)) == acos64(0.0)); +test "math.acos" { + assert(acos_workaround(f32(0.0)) == acos32(0.0)); + assert(acos_workaround(f64(0.0)) == acos64(0.0)); } -test "acos32" { +test "math.acos32" { const epsilon = 0.000001; assert(math.approxEq(f32, acos32(0.0), 1.570796, epsilon)); @@ -153,7 +156,7 @@ test "acos32" { assert(math.approxEq(f32, acos32(-0.2), 1.772154, epsilon)); } -test "acos64" { +test "math.acos64" { const epsilon = 0.000001; assert(math.approxEq(f64, acos64(0.0), 1.570796, epsilon)); diff --git a/std/math/acosh.zig b/std/math/acosh.zig index 7da81360a..96d77261a 100644 --- a/std/math/acosh.zig +++ b/std/math/acosh.zig @@ -1,17 +1,20 @@ const math = @import("index.zig"); const assert = @import("../debug.zig").assert; -pub fn acosh(x: var) -> @typeOf(x) { +pub const acosh = acosh_workaround; + +// TODO issue #393 +pub fn acosh_workaround(x: var) -> @typeOf(x) { const T = @typeOf(x); switch (T) { - f32 => @inlineCall(acoshf, x), - f64 => @inlineCall(acoshd, x), + f32 => @inlineCall(acosh32, x), + f64 => @inlineCall(acosh64, x), else => @compileError("acosh not implemented for " ++ @typeName(T)), } } // acosh(x) = log(x + sqrt(x * x - 1)) -fn acoshf(x: f32) -> f32 { +fn acosh32(x: f32) -> f32 { const u = @bitCast(u32, x); const i = u & 0x7FFFFFFF; @@ -29,7 +32,7 @@ fn acoshf(x: f32) -> f32 { } } -fn acoshd(x: f64) -> f64 { +fn acosh64(x: f64) -> f64 { const u = @bitCast(u64, x); const e = (u >> 52) & 0x7FF; @@ -47,25 +50,25 @@ fn acoshd(x: f64) -> f64 { } } -test "acosh" { - assert(acosh(f32(1.5)) == acoshf(1.5)); - assert(acosh(f64(1.5)) == acoshd(1.5)); +test "math.acosh" { + assert(acosh_workaround(f32(1.5)) == acosh32(1.5)); + assert(acosh_workaround(f64(1.5)) == acosh64(1.5)); } -test "acoshf" { +test "math.acosh32" { const epsilon = 0.000001; - assert(math.approxEq(f32, acoshf(1.5), 0.962424, epsilon)); - assert(math.approxEq(f32, acoshf(37.45), 4.315976, epsilon)); - assert(math.approxEq(f32, acoshf(89.123), 5.183133, epsilon)); - assert(math.approxEq(f32, acoshf(123123.234375), 12.414088, epsilon)); + assert(math.approxEq(f32, acosh32(1.5), 0.962424, epsilon)); + assert(math.approxEq(f32, acosh32(37.45), 4.315976, epsilon)); + assert(math.approxEq(f32, acosh32(89.123), 5.183133, epsilon)); + assert(math.approxEq(f32, acosh32(123123.234375), 12.414088, epsilon)); } -test "acoshd" { +test "math.acosh64" { const epsilon = 0.000001; - assert(math.approxEq(f64, acoshd(1.5), 0.962424, epsilon)); - assert(math.approxEq(f64, acoshd(37.45), 4.315976, epsilon)); - assert(math.approxEq(f64, acoshd(89.123), 5.183133, epsilon)); - assert(math.approxEq(f64, acoshd(123123.234375), 12.414088, epsilon)); + assert(math.approxEq(f64, acosh64(1.5), 0.962424, epsilon)); + assert(math.approxEq(f64, acosh64(37.45), 4.315976, epsilon)); + assert(math.approxEq(f64, acosh64(89.123), 5.183133, epsilon)); + assert(math.approxEq(f64, acosh64(123123.234375), 12.414088, epsilon)); } diff --git a/std/math/asin.zig b/std/math/asin.zig index e671477b3..be8d006ca 100644 --- a/std/math/asin.zig +++ b/std/math/asin.zig @@ -1,7 +1,10 @@ const math = @import("index.zig"); const assert = @import("../debug.zig").assert; -pub fn asin(x: var) -> @typeOf(x) { +pub const asin = asin_workaround; + +// TODO issue #393 +pub fn asin_workaround(x: var) -> @typeOf(x) { const T = @typeOf(x); switch (T) { f32 => @inlineCall(asin32, x), @@ -129,12 +132,12 @@ fn asin64(x: f64) -> f64 { } } -test "asin" { - assert(asin(f32(0.0)) == asin32(0.0)); - assert(asin(f64(0.0)) == asin64(0.0)); +test "math.asin" { + assert(asin_workaround(f32(0.0)) == asin32(0.0)); + assert(asin_workaround(f64(0.0)) == asin64(0.0)); } -test "asin32" { +test "math.asin32" { const epsilon = 0.000001; assert(math.approxEq(f32, asin32(0.0), 0.0, epsilon)); @@ -145,7 +148,7 @@ test "asin32" { assert(math.approxEq(f32, asin32(0.8923), 1.102415, epsilon)); } -test "asin64" { +test "math.asin64" { const epsilon = 0.000001; assert(math.approxEq(f64, asin64(0.0), 0.0, epsilon)); diff --git a/std/math/asinh.zig b/std/math/asinh.zig index 2fa75c9d7..587d1927b 100644 --- a/std/math/asinh.zig +++ b/std/math/asinh.zig @@ -1,17 +1,20 @@ const math = @import("index.zig"); const assert = @import("../debug.zig").assert; -pub fn asinh(x: var) -> @typeOf(x) { +pub const asinh = asinh_workaround; + +// TODO issue #393 +pub fn asinh_workaround(x: var) -> @typeOf(x) { const T = @typeOf(x); switch (T) { - f32 => @inlineCall(asinhf, x), - f64 => @inlineCall(asinhd, x), + f32 => @inlineCall(asinh32, x), + f64 => @inlineCall(asinh64, x), else => @compileError("asinh not implemented for " ++ @typeName(T)), } } // asinh(x) = sign(x) * log(|x| + sqrt(x * x + 1)) ~= x - x^3/6 + o(x^5) -fn asinhf(x: f32) -> f32 { +fn asinh32(x: f32) -> f32 { const u = @bitCast(u32, x); const i = u & 0x7FFFFFFF; const s = i >> 31; @@ -38,7 +41,7 @@ fn asinhf(x: f32) -> f32 { if (s != 0) -rx else rx } -fn asinhd(x: f64) -> f64 { +fn asinh64(x: f64) -> f64 { const u = @bitCast(u64, x); const e = (u >> 52) & 0x7FF; const s = u >> 63; @@ -65,31 +68,31 @@ fn asinhd(x: f64) -> f64 { if (s != 0) -rx else rx } -test "asinh" { - assert(asinh(f32(0.0)) == asinhf(0.0)); - assert(asinh(f64(0.0)) == asinhd(0.0)); +test "math.asinh" { + assert(asinh_workaround(f32(0.0)) == asinh32(0.0)); + assert(asinh_workaround(f64(0.0)) == asinh64(0.0)); } -test "asinhf" { +test "math.asinh32" { const epsilon = 0.000001; - assert(math.approxEq(f32, asinhf(0.0), 0.0, epsilon)); - assert(math.approxEq(f32, asinhf(0.2), 0.198690, epsilon)); - assert(math.approxEq(f32, asinhf(0.8923), 0.803133, epsilon)); - assert(math.approxEq(f32, asinhf(1.5), 1.194763, epsilon)); - assert(math.approxEq(f32, asinhf(37.45), 4.316332, epsilon)); - assert(math.approxEq(f32, asinhf(89.123), 5.183196, epsilon)); - assert(math.approxEq(f32, asinhf(123123.234375), 12.414088, epsilon)); + assert(math.approxEq(f32, asinh32(0.0), 0.0, epsilon)); + assert(math.approxEq(f32, asinh32(0.2), 0.198690, epsilon)); + assert(math.approxEq(f32, asinh32(0.8923), 0.803133, epsilon)); + assert(math.approxEq(f32, asinh32(1.5), 1.194763, epsilon)); + assert(math.approxEq(f32, asinh32(37.45), 4.316332, epsilon)); + assert(math.approxEq(f32, asinh32(89.123), 5.183196, epsilon)); + assert(math.approxEq(f32, asinh32(123123.234375), 12.414088, epsilon)); } -test "asinhd" { +test "math.asinh64" { const epsilon = 0.000001; - assert(math.approxEq(f64, asinhd(0.0), 0.0, epsilon)); - assert(math.approxEq(f64, asinhd(0.2), 0.198690, epsilon)); - assert(math.approxEq(f64, asinhd(0.8923), 0.803133, epsilon)); - assert(math.approxEq(f64, asinhd(1.5), 1.194763, epsilon)); - assert(math.approxEq(f64, asinhd(37.45), 4.316332, epsilon)); - assert(math.approxEq(f64, asinhd(89.123), 5.183196, epsilon)); - assert(math.approxEq(f64, asinhd(123123.234375), 12.414088, epsilon)); + assert(math.approxEq(f64, asinh64(0.0), 0.0, epsilon)); + assert(math.approxEq(f64, asinh64(0.2), 0.198690, epsilon)); + assert(math.approxEq(f64, asinh64(0.8923), 0.803133, epsilon)); + assert(math.approxEq(f64, asinh64(1.5), 1.194763, epsilon)); + assert(math.approxEq(f64, asinh64(37.45), 4.316332, epsilon)); + assert(math.approxEq(f64, asinh64(89.123), 5.183196, epsilon)); + assert(math.approxEq(f64, asinh64(123123.234375), 12.414088, epsilon)); } diff --git a/std/math/atan.zig b/std/math/atan.zig index 094827e00..3e67b47ca 100644 --- a/std/math/atan.zig +++ b/std/math/atan.zig @@ -1,7 +1,10 @@ const math = @import("index.zig"); const assert = @import("../debug.zig").assert; -pub fn atan(x: var) -> @typeOf(x) { +// TODO issue #393 +pub const atan = atan_workaround; + +pub fn atan_workaround(x: var) -> @typeOf(x) { const T = @typeOf(x); switch (T) { f32 => @inlineCall(atan32, x), @@ -201,12 +204,12 @@ fn atan64(x_: f64) -> f64 { } } -test "atan" { - assert(atan(f32(0.2)) == atan32(0.2)); - assert(atan(f64(0.2)) == atan64(0.2)); +test "math.atan" { + assert(atan_workaround(f32(0.2)) == atan32(0.2)); + assert(atan_workaround(f64(0.2)) == atan64(0.2)); } -test "atan32" { +test "math.atan32" { const epsilon = 0.000001; assert(math.approxEq(f32, atan32(0.2), 0.197396, epsilon)); @@ -216,7 +219,7 @@ test "atan32" { assert(math.approxEq(f32, atan32(1.5), 0.982794, epsilon)); } -test "atan64" { +test "math.atan64" { const epsilon = 0.000001; assert(math.approxEq(f64, atan64(0.2), 0.197396, epsilon)); diff --git a/std/math/atan2.zig b/std/math/atan2.zig index 14bcc60ad..ac1fe30da 100644 --- a/std/math/atan2.zig +++ b/std/math/atan2.zig @@ -1,15 +1,18 @@ const math = @import("index.zig"); const assert = @import("../debug.zig").assert; -pub fn atan2(comptime T: type, x: T, y: T) -> T { +pub const atan2 = atan2_workaround; + +// TODO issue #393 +pub fn atan2_workaround(comptime T: type, x: T, y: T) -> T { switch (T) { - f32 => @inlineCall(atan2f, x, y), - f64 => @inlineCall(atan2d, x, y), + f32 => @inlineCall(atan2_32, x, y), + f64 => @inlineCall(atan2_64, x, y), else => @compileError("atan2 not implemented for " ++ @typeName(T)), } } -fn atan2f(y: f32, x: f32) -> f32 { +fn atan2_32(y: f32, x: f32) -> f32 { const pi: f32 = 3.1415927410e+00; const pi_lo: f32 = -8.7422776573e-08; @@ -94,7 +97,7 @@ fn atan2f(y: f32, x: f32) -> f32 { } } -fn atan2d(y: f64, x: f64) -> f64 { +fn atan2_64(y: f64, x: f64) -> f64 { const pi: f64 = 3.1415926535897931160E+00; const pi_lo: f64 = 1.2246467991473531772E-16; @@ -184,31 +187,31 @@ fn atan2d(y: f64, x: f64) -> f64 { } } -test "atan2" { - assert(atan2(f32, 0.2, 0.21) == atan2f(0.2, 0.21)); - assert(atan2(f64, 0.2, 0.21) == atan2d(0.2, 0.21)); +test "math.atan2" { + assert(atan2_workaround(f32, 0.2, 0.21) == atan2_32(0.2, 0.21)); + assert(atan2_workaround(f64, 0.2, 0.21) == atan2_64(0.2, 0.21)); } -test "atan2f" { +test "math.atan2_32" { const epsilon = 0.000001; - assert(math.approxEq(f32, atan2f(0.0, 0.0), 0.0, epsilon)); - assert(math.approxEq(f32, atan2f(0.2, 0.2), 0.785398, epsilon)); - assert(math.approxEq(f32, atan2f(-0.2, 0.2), -0.785398, epsilon)); - assert(math.approxEq(f32, atan2f(0.2, -0.2), 2.356194, epsilon)); - assert(math.approxEq(f32, atan2f(-0.2, -0.2), -2.356194, epsilon)); - assert(math.approxEq(f32, atan2f(0.34, -0.4), 2.437099, epsilon)); - assert(math.approxEq(f32, atan2f(0.34, 1.243), 0.267001, epsilon)); + assert(math.approxEq(f32, atan2_32(0.0, 0.0), 0.0, epsilon)); + assert(math.approxEq(f32, atan2_32(0.2, 0.2), 0.785398, epsilon)); + assert(math.approxEq(f32, atan2_32(-0.2, 0.2), -0.785398, epsilon)); + assert(math.approxEq(f32, atan2_32(0.2, -0.2), 2.356194, epsilon)); + assert(math.approxEq(f32, atan2_32(-0.2, -0.2), -2.356194, epsilon)); + assert(math.approxEq(f32, atan2_32(0.34, -0.4), 2.437099, epsilon)); + assert(math.approxEq(f32, atan2_32(0.34, 1.243), 0.267001, epsilon)); } -test "atan2d" { +test "math.atan2_64" { const epsilon = 0.000001; - assert(math.approxEq(f64, atan2d(0.0, 0.0), 0.0, epsilon)); - assert(math.approxEq(f64, atan2d(0.2, 0.2), 0.785398, epsilon)); - assert(math.approxEq(f64, atan2d(-0.2, 0.2), -0.785398, epsilon)); - assert(math.approxEq(f64, atan2d(0.2, -0.2), 2.356194, epsilon)); - assert(math.approxEq(f64, atan2d(-0.2, -0.2), -2.356194, epsilon)); - assert(math.approxEq(f64, atan2d(0.34, -0.4), 2.437099, epsilon)); - assert(math.approxEq(f64, atan2d(0.34, 1.243), 0.267001, epsilon)); + assert(math.approxEq(f64, atan2_64(0.0, 0.0), 0.0, epsilon)); + assert(math.approxEq(f64, atan2_64(0.2, 0.2), 0.785398, epsilon)); + assert(math.approxEq(f64, atan2_64(-0.2, 0.2), -0.785398, epsilon)); + assert(math.approxEq(f64, atan2_64(0.2, -0.2), 2.356194, epsilon)); + assert(math.approxEq(f64, atan2_64(-0.2, -0.2), -2.356194, epsilon)); + assert(math.approxEq(f64, atan2_64(0.34, -0.4), 2.437099, epsilon)); + assert(math.approxEq(f64, atan2_64(0.34, 1.243), 0.267001, epsilon)); } diff --git a/std/math/atanh.zig b/std/math/atanh.zig index 9098616c5..25540d299 100644 --- a/std/math/atanh.zig +++ b/std/math/atanh.zig @@ -1,17 +1,20 @@ const math = @import("index.zig"); const assert = @import("../debug.zig").assert; -pub fn atanh(x: var) -> @typeOf(x) { +// TODO issue #393 +pub const atanh = atanh_workaround; + +pub fn atanh_workaround(x: var) -> @typeOf(x) { const T = @typeOf(x); switch (T) { - f32 => @inlineCall(atanhf, x), - f64 => @inlineCall(atanhd, x), + f32 => @inlineCall(atanh_32, x), + f64 => @inlineCall(atanh_64, x), else => @compileError("atanh not implemented for " ++ @typeName(T)), } } // atanh(x) = log((1 + x) / (1 - x)) / 2 = log1p(2x / (1 - x)) / 2 ~= x + x^3 / 3 + o(x^5) -fn atanhf(x: f32) -> f32 { +fn atanh_32(x: f32) -> f32 { const u = @bitCast(u32, x); const i = u & 0x7FFFFFFF; const s = u >> 31; @@ -37,7 +40,7 @@ fn atanhf(x: f32) -> f32 { if (s != 0) -y else y } -fn atanhd(x: f64) -> f64 { +fn atanh_64(x: f64) -> f64 { const u = @bitCast(u64, x); const e = (u >> 52) & 0x7FF; const s = u >> 63; @@ -63,23 +66,23 @@ fn atanhd(x: f64) -> f64 { if (s != 0) -y else y } -test "atanh" { - assert(atanh(f32(0.0)) == atanhf(0.0)); - assert(atanh(f64(0.0)) == atanhd(0.0)); +test "math.atanh" { + assert(atanh(f32(0.0)) == atanh_32(0.0)); + assert(atanh(f64(0.0)) == atanh_64(0.0)); } -test "atanhf" { +test "math.atanh_32" { const epsilon = 0.000001; - assert(math.approxEq(f32, atanhf(0.0), 0.0, epsilon)); - assert(math.approxEq(f32, atanhf(0.2), 0.202733, epsilon)); - assert(math.approxEq(f32, atanhf(0.8923), 1.433099, epsilon)); + assert(math.approxEq(f32, atanh_32(0.0), 0.0, epsilon)); + assert(math.approxEq(f32, atanh_32(0.2), 0.202733, epsilon)); + assert(math.approxEq(f32, atanh_32(0.8923), 1.433099, epsilon)); } -test "atanhd" { +test "math.atanh_64" { const epsilon = 0.000001; - assert(math.approxEq(f64, atanhd(0.0), 0.0, epsilon)); - assert(math.approxEq(f64, atanhd(0.2), 0.202733, epsilon)); - assert(math.approxEq(f64, atanhd(0.8923), 1.433099, epsilon)); + assert(math.approxEq(f64, atanh_64(0.0), 0.0, epsilon)); + assert(math.approxEq(f64, atanh_64(0.2), 0.202733, epsilon)); + assert(math.approxEq(f64, atanh_64(0.8923), 1.433099, epsilon)); } diff --git a/std/math/cbrt.zig b/std/math/cbrt.zig index e286f94ab..ac6e90576 100644 --- a/std/math/cbrt.zig +++ b/std/math/cbrt.zig @@ -1,7 +1,10 @@ const math = @import("index.zig"); const assert = @import("../debug.zig").assert; -pub fn cbrt(x: var) -> @typeOf(x) { +// TODO issue #393 +pub const cbrt = cbrt_workaround; + +pub fn cbrt_workaround(x: var) -> @typeOf(x) { const T = @typeOf(x); switch (T) { f32 => @inlineCall(cbrt32, x), @@ -106,12 +109,12 @@ fn cbrt64(x: f64) -> f64 { t + t * q } -test "cbrt" { +test "math.cbrt" { assert(cbrt(f32(0.0)) == cbrt32(0.0)); assert(cbrt(f64(0.0)) == cbrt64(0.0)); } -test "cbrt32" { +test "math.cbrt32" { const epsilon = 0.000001; assert(cbrt32(0.0) == 0.0); @@ -122,7 +125,7 @@ test "cbrt32" { assert(math.approxEq(f32, cbrt32(123123.234375), 49.748501, epsilon)); } -test "cbrt64" { +test "math.cbrt64" { const epsilon = 0.000001; assert(cbrt64(0.0) == 0.0); diff --git a/std/math/ceil.zig b/std/math/ceil.zig index f80e493f1..f5bc22500 100644 --- a/std/math/ceil.zig +++ b/std/math/ceil.zig @@ -2,7 +2,10 @@ const builtin = @import("builtin"); const math = @import("index.zig"); const assert = @import("../debug.zig").assert; -pub fn ceil(x: var) -> @typeOf(x) { +// TODO issue #393 +pub const ceil = ceil_workaround; + +pub fn ceil_workaround(x: var) -> @typeOf(x) { const T = @typeOf(x); switch (T) { f32 => @inlineCall(ceil32, x), @@ -71,18 +74,18 @@ fn ceil64(x: f64) -> f64 { } } -test "ceil" { +test "math.ceil" { assert(ceil(f32(0.0)) == ceil32(0.0)); assert(ceil(f64(0.0)) == ceil64(0.0)); } -test "ceil32" { +test "math.ceil32" { assert(ceil32(1.3) == 2.0); assert(ceil32(-1.3) == -1.0); assert(ceil32(0.2) == 1.0); } -test "ceil64" { +test "math.ceil64" { assert(ceil64(1.3) == 2.0); assert(ceil64(-1.3) == -1.0); assert(ceil64(0.2) == 1.0); diff --git a/std/math/copysign.zig b/std/math/copysign.zig index 7043cc485..8c2edeb28 100644 --- a/std/math/copysign.zig +++ b/std/math/copysign.zig @@ -1,7 +1,10 @@ const math = @import("index.zig"); const assert = @import("../debug.zig").assert; -pub fn copysign(comptime T: type, x: T, y: T) -> T { +// TODO issue #393 +pub const copysign = copysign_workaround; + +pub fn copysign_workaround(comptime T: type, x: T, y: T) -> T { switch (T) { f32 => @inlineCall(copysign32, x, y), f64 => @inlineCall(copysign64, x, y), @@ -27,19 +30,19 @@ fn copysign64(x: f64, y: f64) -> f64 { @bitCast(f64, h1 | h2) } -test "copysign" { +test "math.copysign" { assert(copysign(f32, 1.0, 1.0) == copysign32(1.0, 1.0)); assert(copysign(f64, 1.0, 1.0) == copysign64(1.0, 1.0)); } -test "copysign32" { +test "math.copysign32" { assert(copysign32(5.0, 1.0) == 5.0); assert(copysign32(5.0, -1.0) == -5.0); assert(copysign32(-5.0, -1.0) == -5.0); assert(copysign32(-5.0, 1.0) == 5.0); } -test "copysign64" { +test "math.copysign64" { assert(copysign64(5.0, 1.0) == 5.0); assert(copysign64(5.0, -1.0) == -5.0); assert(copysign64(-5.0, -1.0) == -5.0); diff --git a/std/math/cos.zig b/std/math/cos.zig index bb77f6a5b..8b5a1211e 100644 --- a/std/math/cos.zig +++ b/std/math/cos.zig @@ -1,7 +1,11 @@ const math = @import("index.zig"); const assert = @import("../debug.zig").assert; -pub fn cos(x: var) -> @typeOf(x) { + +// TODO issue #393 +pub const cos = cos_workaround; + +pub fn cos_workaround(x: var) -> @typeOf(x) { const T = @typeOf(x); switch (T) { f32 => @inlineCall(cos32, x), @@ -133,12 +137,12 @@ fn cos64(x_: f64) -> f64 { } } -test "cos" { +test "math.cos" { assert(cos(f32(0.0)) == cos32(0.0)); assert(cos(f64(0.0)) == cos64(0.0)); } -test "cos32" { +test "math.cos32" { const epsilon = 0.000001; assert(math.approxEq(f32, cos32(0.0), 1.0, epsilon)); @@ -149,7 +153,7 @@ test "cos32" { assert(math.approxEq(f32, cos32(89.123), 0.400798, epsilon)); } -test "cos64" { +test "math.cos64" { const epsilon = 0.000001; assert(math.approxEq(f64, cos64(0.0), 1.0, epsilon)); diff --git a/std/math/cosh.zig b/std/math/cosh.zig index 60bff79b2..5eba8baa5 100644 --- a/std/math/cosh.zig +++ b/std/math/cosh.zig @@ -2,11 +2,14 @@ const math = @import("index.zig"); const expo2 = @import("_expo2.zig").expo2; const assert = @import("../debug.zig").assert; -pub fn cosh(x: var) -> @typeOf(x) { +// TODO issue #393 +pub const cosh = cosh_workaround; + +pub fn cosh_workaround(x: var) -> @typeOf(x) { const T = @typeOf(x); switch (T) { - f32 => @inlineCall(coshf, x), - f64 => @inlineCall(coshd, x), + f32 => @inlineCall(cosh32, x), + f64 => @inlineCall(cosh64, x), else => @compileError("cosh not implemented for " ++ @typeName(T)), } } @@ -14,7 +17,7 @@ pub fn cosh(x: var) -> @typeOf(x) { // cosh(x) = (exp(x) + 1 / exp(x)) / 2 // = 1 + 0.5 * (exp(x) - 1) * (exp(x) - 1) / exp(x) // = 1 + (x * x) / 2 + o(x^4) -fn coshf(x: f32) -> f32 { +fn cosh32(x: f32) -> f32 { const u = @bitCast(u32, x); const ux = u & 0x7FFFFFFF; const ax = @bitCast(f32, ux); @@ -39,7 +42,7 @@ fn coshf(x: f32) -> f32 { expo2(ax) } -fn coshd(x: f64) -> f64 { +fn cosh64(x: f64) -> f64 { const u = @bitCast(u64, x); const w = u32(u >> 32); const ax = @bitCast(f64, u & (@maxValue(u64) >> 1)); @@ -67,25 +70,25 @@ fn coshd(x: f64) -> f64 { expo2(ax) } -test "cosh" { - assert(cosh(f32(1.5)) == coshf(1.5)); - assert(cosh(f64(1.5)) == coshd(1.5)); +test "math.cosh" { + assert(cosh(f32(1.5)) == cosh32(1.5)); + assert(cosh(f64(1.5)) == cosh64(1.5)); } -test "coshf" { +test "math.cosh32" { const epsilon = 0.000001; - assert(math.approxEq(f32, coshf(0.0), 1.0, epsilon)); - assert(math.approxEq(f32, coshf(0.2), 1.020067, epsilon)); - assert(math.approxEq(f32, coshf(0.8923), 1.425225, epsilon)); - assert(math.approxEq(f32, coshf(1.5), 2.352410, epsilon)); + assert(math.approxEq(f32, cosh32(0.0), 1.0, epsilon)); + assert(math.approxEq(f32, cosh32(0.2), 1.020067, epsilon)); + assert(math.approxEq(f32, cosh32(0.8923), 1.425225, epsilon)); + assert(math.approxEq(f32, cosh32(1.5), 2.352410, epsilon)); } -test "coshd" { +test "math.cosh64" { const epsilon = 0.000001; - assert(math.approxEq(f64, coshd(0.0), 1.0, epsilon)); - assert(math.approxEq(f64, coshd(0.2), 1.020067, epsilon)); - assert(math.approxEq(f64, coshd(0.8923), 1.425225, epsilon)); - assert(math.approxEq(f64, coshd(1.5), 2.352410, epsilon)); + assert(math.approxEq(f64, cosh64(0.0), 1.0, epsilon)); + assert(math.approxEq(f64, cosh64(0.2), 1.020067, epsilon)); + assert(math.approxEq(f64, cosh64(0.8923), 1.425225, epsilon)); + assert(math.approxEq(f64, cosh64(1.5), 2.352410, epsilon)); } diff --git a/std/math/exp.zig b/std/math/exp.zig index 2efbbeccc..0e35108a9 100644 --- a/std/math/exp.zig +++ b/std/math/exp.zig @@ -1,7 +1,10 @@ const math = @import("index.zig"); const assert = @import("../debug.zig").assert; -pub fn exp(x: var) -> @typeOf(x) { +// TODO issue #393 +pub const exp = exp_workaround; + +pub fn exp_workaround(x: var) -> @typeOf(x) { const T = @typeOf(x); switch (T) { f32 => @inlineCall(exp32, x), @@ -165,12 +168,12 @@ fn exp64(x_: f64) -> f64 { } } -test "exp" { +test "math.exp" { assert(exp(f32(0.0)) == exp32(0.0)); assert(exp(f64(0.0)) == exp64(0.0)); } -test "exp32" { +test "math.exp32" { const epsilon = 0.000001; assert(exp32(0.0) == 1.0); @@ -180,7 +183,7 @@ test "exp32" { assert(math.approxEq(f32, exp32(1.5), 4.481689, epsilon)); } -test "exp64" { +test "math.exp64" { const epsilon = 0.000001; assert(exp64(0.0) == 1.0); diff --git a/std/math/exp2.zig b/std/math/exp2.zig index db3b1757e..5b135a7b2 100644 --- a/std/math/exp2.zig +++ b/std/math/exp2.zig @@ -1,11 +1,14 @@ const math = @import("index.zig"); const assert = @import("../debug.zig").assert; -pub fn exp2(x: var) -> @typeOf(x) { +// TODO issue #393 +pub const exp2 = exp2_workaround; + +pub fn exp2_workaround(x: var) -> @typeOf(x) { const T = @typeOf(x); switch (T) { - f32 => @inlineCall(exp2f, x), - f64 => @inlineCall(exp2d, x), + f32 => @inlineCall(exp2_32, x), + f64 => @inlineCall(exp2_64, x), else => @compileError("exp2 not implemented for " ++ @typeName(T)), } } @@ -29,7 +32,7 @@ const exp2ft = []const f64 { 0x1.5ab07dd485429p+0, }; -fn exp2f(x: f32) -> f32 { +fn exp2_32(x: f32) -> f32 { @setFloatMode(this, @import("builtin").FloatMode.Strict); const tblsiz = u32(exp2ft.len); @@ -346,7 +349,7 @@ const exp2dt = []f64 { 0x1.690f4b19e9471p+0, -0x1.9780p-45, }; -fn exp2d(x: f64) -> f64 { +fn exp2_64(x: f64) -> f64 { @setFloatMode(this, @import("builtin").FloatMode.Strict); const tblsiz = u32(exp2dt.len / 2); @@ -407,27 +410,27 @@ fn exp2d(x: f64) -> f64 { math.scalbn(r, ik) } -test "exp2" { - assert(exp2(f32(0.8923)) == exp2f(0.8923)); - assert(exp2(f64(0.8923)) == exp2d(0.8923)); +test "math.exp2" { + assert(exp2(f32(0.8923)) == exp2_32(0.8923)); + assert(exp2(f64(0.8923)) == exp2_64(0.8923)); } -test "exp2f" { +test "math.exp2_32" { const epsilon = 0.000001; - assert(exp2f(0.0) == 1.0); - assert(math.approxEq(f32, exp2f(0.2), 1.148698, epsilon)); - assert(math.approxEq(f32, exp2f(0.8923), 1.856133, epsilon)); - assert(math.approxEq(f32, exp2f(1.5), 2.828427, epsilon)); - assert(math.approxEq(f32, exp2f(37.45), 187747237888, epsilon)); + assert(exp2_32(0.0) == 1.0); + assert(math.approxEq(f32, exp2_32(0.2), 1.148698, epsilon)); + assert(math.approxEq(f32, exp2_32(0.8923), 1.856133, epsilon)); + assert(math.approxEq(f32, exp2_32(1.5), 2.828427, epsilon)); + assert(math.approxEq(f32, exp2_32(37.45), 187747237888, epsilon)); } -test "exp2d" { +test "math.exp2_64" { const epsilon = 0.000001; - assert(exp2d(0.0) == 1.0); - assert(math.approxEq(f64, exp2d(0.2), 1.148698, epsilon)); - assert(math.approxEq(f64, exp2d(0.8923), 1.856133, epsilon)); - assert(math.approxEq(f64, exp2d(1.5), 2.828427, epsilon)); - // assert(math.approxEq(f64, exp2d(37.45), 18379273786760560.000000, epsilon)); + assert(exp2_64(0.0) == 1.0); + assert(math.approxEq(f64, exp2_64(0.2), 1.148698, epsilon)); + assert(math.approxEq(f64, exp2_64(0.8923), 1.856133, epsilon)); + assert(math.approxEq(f64, exp2_64(1.5), 2.828427, epsilon)); + // assert(math.approxEq(f64, exp2_64(37.45), 18379273786760560.000000, epsilon)); } diff --git a/std/math/expm1.zig b/std/math/expm1.zig index 7b089e023..c54913299 100644 --- a/std/math/expm1.zig +++ b/std/math/expm1.zig @@ -1,16 +1,19 @@ const math = @import("index.zig"); const assert = @import("../debug.zig").assert; -pub fn expm1(x: var) -> @typeOf(x) { +// TODO issue #393 +pub const expm1 = expm1_workaround; + +pub fn expm1_workaround(x: var) -> @typeOf(x) { const T = @typeOf(x); switch (T) { - f32 => @inlineCall(expm1f, x), - f64 => @inlineCall(expm1d, x), + f32 => @inlineCall(expm1_32, x), + f64 => @inlineCall(expm1_64, x), else => @compileError("exp1m not implemented for " ++ @typeName(T)), } } -fn expm1f(x_: f32) -> f32 { +fn expm1_32(x_: f32) -> f32 { const o_threshold: f32 = 8.8721679688e+01; const ln2_hi: f32 = 6.9313812256e-01; const ln2_lo: f32 = 9.0580006145e-06; @@ -131,7 +134,7 @@ fn expm1f(x_: f32) -> f32 { } } -fn expm1d(x_: f64) -> f64 { +fn expm1_64(x_: f64) -> f64 { const o_threshold: f64 = 7.09782712893383973096e+02; const ln2_hi: f64 = 6.93147180369123816490e-01; const ln2_lo: f64 = 1.90821492927058770002e-10; @@ -256,27 +259,27 @@ fn expm1d(x_: f64) -> f64 { } } -test "exp1m" { - assert(expm1(f32(0.0)) == expm1f(0.0)); - assert(expm1(f64(0.0)) == expm1d(0.0)); +test "math.exp1m" { + assert(expm1(f32(0.0)) == expm1_32(0.0)); + assert(expm1(f64(0.0)) == expm1_64(0.0)); } -test "expm1f" { +test "math.expm1_32" { const epsilon = 0.000001; - assert(expm1f(0.0) == 0.0); - assert(math.approxEq(f32, expm1f(0.0), 0.0, epsilon)); - assert(math.approxEq(f32, expm1f(0.2), 0.221403, epsilon)); - assert(math.approxEq(f32, expm1f(0.8923), 1.440737, epsilon)); - assert(math.approxEq(f32, expm1f(1.5), 3.481689, epsilon)); + assert(expm1_32(0.0) == 0.0); + assert(math.approxEq(f32, expm1_32(0.0), 0.0, epsilon)); + assert(math.approxEq(f32, expm1_32(0.2), 0.221403, epsilon)); + assert(math.approxEq(f32, expm1_32(0.8923), 1.440737, epsilon)); + assert(math.approxEq(f32, expm1_32(1.5), 3.481689, epsilon)); } -test "expm1d" { +test "math.expm1_64" { const epsilon = 0.000001; - assert(expm1d(0.0) == 0.0); - assert(math.approxEq(f64, expm1d(0.0), 0.0, epsilon)); - assert(math.approxEq(f64, expm1d(0.2), 0.221403, epsilon)); - assert(math.approxEq(f64, expm1d(0.8923), 1.440737, epsilon)); - assert(math.approxEq(f64, expm1d(1.5), 3.481689, epsilon)); + assert(expm1_64(0.0) == 0.0); + assert(math.approxEq(f64, expm1_64(0.0), 0.0, epsilon)); + assert(math.approxEq(f64, expm1_64(0.2), 0.221403, epsilon)); + assert(math.approxEq(f64, expm1_64(0.8923), 1.440737, epsilon)); + assert(math.approxEq(f64, expm1_64(1.5), 3.481689, epsilon)); } diff --git a/std/math/fabs.zig b/std/math/fabs.zig index 128d4eae7..1e8e0b5e1 100644 --- a/std/math/fabs.zig +++ b/std/math/fabs.zig @@ -1,7 +1,10 @@ const math = @import("index.zig"); const assert = @import("../debug.zig").assert; -pub fn fabs(x: var) -> @typeOf(x) { +// TODO issue #393 +pub const fabs = fabs_workaround; + +pub fn fabs_workaround(x: var) -> @typeOf(x) { const T = @typeOf(x); switch (T) { f32 => @inlineCall(fabs32, x), @@ -22,17 +25,17 @@ fn fabs64(x: f64) -> f64 { @bitCast(f64, u) } -test "fabs" { +test "math.fabs" { assert(fabs(f32(1.0)) == fabs32(1.0)); assert(fabs(f64(1.0)) == fabs64(1.0)); } -test "fabs32" { +test "math.fabs32" { assert(fabs64(1.0) == 1.0); assert(fabs64(-1.0) == 1.0); } -test "fabs64" { +test "math.fabs64" { assert(fabs64(1.0) == 1.0); assert(fabs64(-1.0) == 1.0); } diff --git a/std/math/floor.zig b/std/math/floor.zig index af1ee98be..7c0b6c414 100644 --- a/std/math/floor.zig +++ b/std/math/floor.zig @@ -2,7 +2,10 @@ const builtin = @import("builtin"); const assert = @import("../debug.zig").assert; const math = @import("index.zig"); -pub fn floor(x: var) -> @typeOf(x) { +// TODO issue #393 +pub const floor = floor_workaround; + +pub fn floor_workaround(x: var) -> @typeOf(x) { const T = @typeOf(x); switch (T) { f32 => @inlineCall(floor32, x), @@ -71,18 +74,18 @@ fn floor64(x: f64) -> f64 { } } -test "floor" { +test "math.floor" { assert(floor(f32(1.3)) == floor32(1.3)); assert(floor(f64(1.3)) == floor64(1.3)); } -test "floor32" { +test "math.floor32" { assert(floor32(1.3) == 1.0); assert(floor32(-1.3) == -2.0); assert(floor32(0.2) == 0.0); } -test "floor64" { +test "math.floor64" { assert(floor64(1.3) == 1.0); assert(floor64(-1.3) == -2.0); assert(floor64(0.2) == 0.0); diff --git a/std/math/fma.zig b/std/math/fma.zig index 2ff57b968..4545fc20f 100644 --- a/std/math/fma.zig +++ b/std/math/fma.zig @@ -1,7 +1,10 @@ const math = @import("index.zig"); const assert = @import("../debug.zig").assert; -pub fn fma(comptime T: type, x: T, y: T, z: T) -> T { +// TODO issue #393 +pub const fma = fma_workaround; + +pub fn fma_workaround(comptime T: type, x: T, y: T, z: T) -> T { switch (T) { f32 => @inlineCall(fma32, x, y, z), f64 => @inlineCall(fma64, x, y ,z), @@ -130,12 +133,12 @@ fn add_and_denorm(a: f64, b: f64, scale: i32) -> f64 { math.scalbn(sum.hi, scale) } -test "fma" { +test "math.fma" { assert(fma(f32, 0.0, 1.0, 1.0) == fma32(0.0, 1.0, 1.0)); assert(fma(f64, 0.0, 1.0, 1.0) == fma64(0.0, 1.0, 1.0)); } -test "fma32" { +test "math.fma32" { const epsilon = 0.000001; assert(math.approxEq(f32, fma32(0.0, 5.0, 9.124), 9.124, epsilon)); @@ -147,7 +150,7 @@ test "fma32" { assert(math.approxEq(f32, fma32(123123.234375, 5.0, 9.124), 615625.295875, epsilon)); } -test "fma64" { +test "math.fma64" { const epsilon = 0.000001; assert(math.approxEq(f64, fma64(0.0, 5.0, 9.124), 9.124, epsilon)); diff --git a/std/math/fmod.zig b/std/math/fmod.zig deleted file mode 100644 index 8cc9586bc..000000000 --- a/std/math/fmod.zig +++ /dev/null @@ -1,190 +0,0 @@ -const math = @import("index.zig"); -const assert = @import("../debug.zig").assert; - -pub fn fmod(comptime T: type, x: T, y: T) -> T { - switch (T) { - f32 => @inlineCall(fmod32, x, y), - f64 => @inlineCall(fmod64, x, y), - else => @compileError("fmod not implemented for " ++ @typeName(T)), - } -} - -fn fmod32(x: f32, y: f32) -> f32 { - var ux = @bitCast(u32, x); - var uy = @bitCast(u32, y); - var ex = i32(ux >> 23) & 0xFF; - var ey = i32(ux >> 23) & 0xFF; - const sx = ux & 0x80000000; - - if (uy << 1 == 0 or math.isNan(y) or ex == 0xFF) { - return (x * y) / (x * y); - } - if (ux << 1 <= uy << 1) { - if (ux << 1 == uy << 1) { - return 0 * x; - } else { - return x; - } - } - - // normalize x and y - if (ex == 0) { - var i = ux << 9; - while (i >> 31 == 0) : (i <<= 1) { - ex -= 1; - } - ux <<= u32(-ex + 1); - } else { - ux &= @maxValue(u32) >> 9; - ux |= 1 << 23; - } - - if (ey == 0) { - var i = uy << 9; - while (i >> 31 == 0) : (i <<= 1) { - ey -= 1; - } - uy <<= u32(-ey + 1); - } else { - uy &= @maxValue(u32) >> 9; - uy |= 1 << 23; - } - - // x mod y - while (ex > ey) : (ex -= 1) { - const i = ux - uy; - if (i >> 31 == 0) { - if (i == 0) { - return 0 * x; - } - ux = i; - } - ux <<= 1; - } - { - const i = ux - uy; - if (i >> 31 == 0) { - if (i == 0) { - return 0 * x; - } - ux = i; - } - } - - while (ux >> 23 == 0) : (ux <<= 1) { - ex -= 1; - } - - // scale result up - if (ex > 0) { - ux -= 1 << 23; - ux |= u32(ex) << 23; - } else { - ux >>= u32(-ex + 1); - } - - ux |= sx; - @bitCast(f32, ux) -} - -fn fmod64(x: f64, y: f64) -> f64 { - var ux = @bitCast(u64, x); - var uy = @bitCast(u64, y); - var ex = i32(ux >> 52) & 0x7FF; - var ey = i32(ux >> 52) & 0x7FF; - const sx = ux >> 63; - - if (uy << 1 == 0 or math.isNan(y) or ex == 0x7FF) { - return (x * y) / (x * y); - } - if (ux << 1 <= uy << 1) { - if (ux << 1 == uy << 1) { - return 0 * x; - } else { - return x; - } - } - - // normalize x and y - if (ex == 0) { - var i = ux << 12; - while (i >> 63 == 0) : (i <<= 1) { - ex -= 1; - } - ux <<= u64(-ex + 1); - } else { - ux &= @maxValue(u64) >> 12; - ux |= 1 << 52; - } - - if (ey == 0) { - var i = uy << 12; - while (i >> 63 == 0) : (i <<= 1) { - ey -= 1; - } - uy <<= u64(-ey + 1); - } else { - uy &= @maxValue(u64) >> 12; - uy |= 1 << 52; - } - - // x mod y - while (ex > ey) : (ex -= 1) { - const i = ux - uy; - if (i >> 63 == 0) { - if (i == 0) { - return 0 * x; - } - ux = i; - } - ux <<= 1; - } - { - const i = ux - uy; - if (i >> 63 == 0) { - if (i == 0) { - return 0 * x; - } - ux = i; - } - } - - while (ux >> 52 == 0) : (ux <<= 1) { - ex -= 1; - } - - // scale result up - if (ex > 0) { - ux -= 1 << 52; - ux |= u64(ex) << 52; - } else { - ux >>= u64(-ex + 1); - } - - ux |= sx << 63; - @bitCast(f64, ux) -} - -// duplicate symbol clash with `fmod` test name -test "fmod_" { - assert(fmod(f32, 1.3, 2.5) == fmod32(1.3, 2.5)); - assert(fmod(f64, 1.3, 2.5) == fmod64(1.3, 2.5)); -} - -test "fmod32" { - const epsilon = 0.000001; - - assert(math.approxEq(f32, fmod32(5.2, 2.0), 1.2, epsilon)); - assert(math.approxEq(f32, fmod32(18.5, 4.2), 1.7, epsilon)); - assert(math.approxEq(f32, fmod32(23, 48.34), 23.0, epsilon)); - assert(math.approxEq(f32, fmod32(123.340890, 2398.2314), 123.340889, epsilon)); -} - -test "fmod64" { - const epsilon = 0.000001; - - assert(math.approxEq(f64, fmod64(5.2, 2.0), 1.2, epsilon)); - assert(math.approxEq(f64, fmod64(18.5, 4.2), 1.7, epsilon)); - assert(math.approxEq(f64, fmod64(23, 48.34), 23.0, epsilon)); - assert(math.approxEq(f64, fmod64(123.340890, 2398.2314), 123.340889, epsilon)); -} diff --git a/std/math/frexp.zig b/std/math/frexp.zig index a96ae8f37..e0c6975e1 100644 --- a/std/math/frexp.zig +++ b/std/math/frexp.zig @@ -1,6 +1,9 @@ const math = @import("index.zig"); const assert = @import("../debug.zig").assert; +// TODO issue #393 +pub const frexp = frexp_workaround; + fn frexp_result(comptime T: type) -> type { struct { significand: T, @@ -10,7 +13,7 @@ fn frexp_result(comptime T: type) -> type { pub const frexp32_result = frexp_result(f32); pub const frexp64_result = frexp_result(f64); -pub fn frexp(x: var) -> frexp_result(@typeOf(x)) { +pub fn frexp_workaround(x: var) -> frexp_result(@typeOf(x)) { const T = @typeOf(x); switch (T) { f32 => @inlineCall(frexp32, x), @@ -80,7 +83,7 @@ fn frexp64(x: f64) -> frexp64_result { result } -test "frexp" { +test "math.frexp" { const a = frexp(f32(1.3)); const b = frexp32(1.3); assert(a.significand == b.significand and a.exponent == b.exponent); @@ -90,7 +93,7 @@ test "frexp" { assert(c.significand == d.significand and c.exponent == d.exponent); } -test "frexp32" { +test "math.frexp32" { const epsilon = 0.000001; var r: frexp32_result = undefined; @@ -101,7 +104,7 @@ test "frexp32" { assert(math.approxEq(f32, r.significand, 0.609558, epsilon) and r.exponent == 7); } -test "frexp64" { +test "math.frexp64" { const epsilon = 0.000001; var r: frexp64_result = undefined; diff --git a/std/math/hypot.zig b/std/math/hypot.zig index 61a37f140..636c1707f 100644 --- a/std/math/hypot.zig +++ b/std/math/hypot.zig @@ -1,7 +1,10 @@ const math = @import("index.zig"); const assert = @import("../debug.zig").assert; -pub fn hypot(comptime T: type, x: T, y: T) -> T { +// TODO issue #393 +pub const hypot = hypot_workaround; + +pub fn hypot_workaround(comptime T: type, x: T, y: T) -> T { switch (T) { f32 => @inlineCall(hypot32, x, y), f64 => @inlineCall(hypot64, x, y), @@ -105,12 +108,12 @@ fn hypot64(x: f64, y: f64) -> f64 { z * math.sqrt(ly + lx + hy + hx) } -test "hypot" { +test "math.hypot" { assert(hypot(f32, 0.0, -1.2) == hypot32(0.0, -1.2)); assert(hypot(f64, 0.0, -1.2) == hypot64(0.0, -1.2)); } -test "hypot32" { +test "math.hypot32" { const epsilon = 0.000001; assert(math.approxEq(f32, hypot32(0.0, -1.2), 1.2, epsilon)); @@ -122,7 +125,7 @@ test "hypot32" { assert(math.approxEq(f32, hypot32(123123.234375, 529428.707813), 543556.875, epsilon)); } -test "hypot64" { +test "math.hypot64" { const epsilon = 0.000001; assert(math.approxEq(f64, hypot64(0.0, -1.2), 1.2, epsilon)); diff --git a/std/math/ilogb.zig b/std/math/ilogb.zig index 8528a19e2..f045bb623 100644 --- a/std/math/ilogb.zig +++ b/std/math/ilogb.zig @@ -1,7 +1,10 @@ const math = @import("index.zig"); const assert = @import("../debug.zig").assert; -pub fn ilogb(x: var) -> i32 { +// TODO issue #393 +pub const ilogb = ilogb_workaround; + +pub fn ilogb_workaround(x: var) -> i32 { const T = @typeOf(x); switch (T) { f32 => @inlineCall(ilogb32, x), @@ -76,12 +79,12 @@ fn ilogb64(x: f64) -> i32 { e - 0x3FF } -test "ilogb" { +test "math.ilogb" { assert(ilogb(f32(0.2)) == ilogb32(0.2)); assert(ilogb(f64(0.2)) == ilogb64(0.2)); } -test "ilogb32" { +test "math.ilogb32" { assert(ilogb32(0.0) == fp_ilogb0); assert(ilogb32(0.5) == -1); assert(ilogb32(0.8923) == -1); @@ -90,7 +93,7 @@ test "ilogb32" { assert(ilogb32(2398.23) == 11); } -test "ilogb64" { +test "math.ilogb64" { assert(ilogb64(0.0) == fp_ilogb0); assert(ilogb64(0.5) == -1); assert(ilogb64(0.8923) == -1); diff --git a/std/math/index.zig b/std/math/index.zig index b031bba25..d2babbddb 100644 --- a/std/math/index.zig +++ b/std/math/index.zig @@ -98,7 +98,6 @@ pub const round = @import("round.zig").round; pub const frexp = @import("frexp.zig").frexp; pub const frexp32_result = @import("frexp.zig").frexp32_result; pub const frexp64_result = @import("frexp.zig").frexp64_result; -pub const fmod = @import("fmod.zig").fmod; pub const modf = @import("modf.zig").modf; pub const modf32_result = @import("modf.zig").modf32_result; pub const modf64_result = @import("modf.zig").modf64_result; @@ -147,7 +146,6 @@ test "math" { _ = @import("trunc.zig"); _ = @import("round.zig"); _ = @import("frexp.zig"); - _ = @import("fmod.zig"); _ = @import("modf.zig"); _ = @import("copysign.zig"); _ = @import("isfinite.zig"); diff --git a/std/math/isfinite.zig b/std/math/isfinite.zig index a820cb2f5..6dbf98472 100644 --- a/std/math/isfinite.zig +++ b/std/math/isfinite.zig @@ -18,7 +18,7 @@ pub fn isFinite(x: var) -> bool { } } -test "isFinite" { +test "math.isFinite" { assert(isFinite(f32(0.0))); assert(isFinite(f32(-0.0))); assert(isFinite(f64(0.0))); diff --git a/std/math/isinf.zig b/std/math/isinf.zig index cfb8aae55..b388fabf1 100644 --- a/std/math/isinf.zig +++ b/std/math/isinf.zig @@ -48,7 +48,7 @@ pub fn isNegativeInf(x: var) -> bool { } } -test "isInf" { +test "math.isInf" { assert(!isInf(f32(0.0))); assert(!isInf(f32(-0.0))); assert(!isInf(f64(0.0))); @@ -59,7 +59,7 @@ test "isInf" { assert(isInf(-math.inf(f64))); } -test "isPositiveInf" { +test "math.isPositiveInf" { assert(!isPositiveInf(f32(0.0))); assert(!isPositiveInf(f32(-0.0))); assert(!isPositiveInf(f64(0.0))); @@ -70,7 +70,7 @@ test "isPositiveInf" { assert(!isPositiveInf(-math.inf(f64))); } -test "isNegativeInf" { +test "math.isNegativeInf" { assert(!isNegativeInf(f32(0.0))); assert(!isNegativeInf(f32(-0.0))); assert(!isNegativeInf(f64(0.0))); diff --git a/std/math/isnan.zig b/std/math/isnan.zig index 6d3951a3f..b6fce507c 100644 --- a/std/math/isnan.zig +++ b/std/math/isnan.zig @@ -18,7 +18,7 @@ pub fn isNan(x: var) -> bool { } } -test "isNan" { +test "math.isNan" { assert(isNan(math.nan(f32))); assert(isNan(math.nan(f64))); assert(!isNan(f32(1.0))); diff --git a/std/math/isnormal.zig b/std/math/isnormal.zig index 597a7d884..b212d204d 100644 --- a/std/math/isnormal.zig +++ b/std/math/isnormal.zig @@ -18,7 +18,7 @@ pub fn isNormal(x: var) -> bool { } } -test "isNormal" { +test "math.isNormal" { assert(!isNormal(math.nan(f32))); assert(!isNormal(math.nan(f64))); assert(isNormal(f32(1.0))); diff --git a/std/math/ln.zig b/std/math/ln.zig index 5e13be811..9a695d692 100644 --- a/std/math/ln.zig +++ b/std/math/ln.zig @@ -1,7 +1,9 @@ const math = @import("index.zig"); const assert = @import("../debug.zig").assert; -pub fn ln(x: var) -> @typeOf(x) { +pub const ln = ln_workaround; + +pub fn ln_workaround(x: var) -> @typeOf(x) { const T = @typeOf(x); switch (T) { f32 => @inlineCall(lnf, x), diff --git a/std/math/log.zig b/std/math/log.zig index abd480b6a..90f28ffc5 100644 --- a/std/math/log.zig +++ b/std/math/log.zig @@ -2,7 +2,10 @@ const math = @import("index.zig"); const builtin = @import("builtin"); const assert = @import("../debug.zig").assert; -pub fn log(comptime base: usize, x: var) -> @typeOf(x) { +// TODO issue #393 +pub const log = log_workaround; + +pub fn log_workaround(comptime base: usize, x: var) -> @typeOf(x) { const T = @typeOf(x); switch (@typeId(T)) { builtin.TypeId.Int => { @@ -13,8 +16,21 @@ pub fn log(comptime base: usize, x: var) -> @typeOf(x) { } }, - builtin.TypeId.Float => { - return logf(base, x); + builtin.TypeId.Float => switch (T) { + f32 => switch (base) { + 2 => return math.log2(x), + 10 => return math.log10(x), + else => return f32(math.ln(f64(x)) / math.ln(f64(base))), + }, + + f64 => switch (base) { + 2 => return math.log2(x), + 10 => return math.log10(x), + // NOTE: This likely is computed with reduced accuracy. + else => return math.ln(x) / math.ln(f64(base)), + }, + + else => @compileError("log not implemented for " ++ @typeName(T)), }, else => { @@ -23,31 +39,7 @@ pub fn log(comptime base: usize, x: var) -> @typeOf(x) { } } -fn logf(comptime base: usize, x: var) -> @typeOf(x) { - const T = @typeOf(x); - switch (T) { - f32 => { - switch (base) { - 2 => return math.log2(x), - 10 => return math.log10(x), - else => return f32(math.ln(f64(x)) / math.ln(f64(base))), - } - }, - - f64 => { - switch (base) { - 2 => return math.log2(x), - 10 => return math.log10(x), - // NOTE: This likely is computed with reduced accuracy. - else => return math.ln(x) / math.ln(f64(base)), - } - }, - - else => @compileError("log not implemented for " ++ @typeName(T)), - } -} - -test "log_integer" { +test "math.log integer" { assert(log(2, u8(0x1)) == 0); assert(log(2, u8(0x2)) == 1); assert(log(2, i16(0x72)) == 6); @@ -55,7 +47,7 @@ test "log_integer" { assert(log(2, u64(0x7FF0123456789ABC)) == 62); } -test "log_float" { +test "math.log float" { const epsilon = 0.000001; assert(math.approxEq(f32, log(6, f32(0.23947)), -0.797723, epsilon)); @@ -63,7 +55,7 @@ test "log_float" { assert(math.approxEq(f64, log(123897, f64(12389216414)), 1.981724596, epsilon)); } -test "log_float_special" { +test "math.log float_special" { assert(log(2, f32(0.2301974)) == math.log2(f32(0.2301974))); assert(log(10, f32(0.2301974)) == math.log10(f32(0.2301974))); diff --git a/std/math/log10.zig b/std/math/log10.zig index 4a4d2a02e..c48043834 100644 --- a/std/math/log10.zig +++ b/std/math/log10.zig @@ -1,16 +1,19 @@ const math = @import("index.zig"); const assert = @import("../debug.zig").assert; -pub fn log10(x: var) -> @typeOf(x) { +// TODO issue #393 +pub const log10 = log10_workaround; + +pub fn log10_workaround(x: var) -> @typeOf(x) { const T = @typeOf(x); switch (T) { - f32 => @inlineCall(log10f, x), - f64 => @inlineCall(log10d, x), + f32 => @inlineCall(log10_32, x), + f64 => @inlineCall(log10_64, x), else => @compileError("log10 not implemented for " ++ @typeName(T)), } } -fn log10f(x_: f32) -> f32 { +fn log10_32(x_: f32) -> f32 { const ivln10hi: f32 = 4.3432617188e-01; const ivln10lo: f32 = -3.1689971365e-05; const log10_2hi: f32 = 3.0102920532e-01; @@ -70,7 +73,7 @@ fn log10f(x_: f32) -> f32 { dk * log10_2lo + (lo + hi) * ivln10lo + lo * ivln10hi + hi * ivln10hi + dk * log10_2hi } -fn log10d(x_: f64) -> f64 { +fn log10_64(x_: f64) -> f64 { const ivln10hi: f64 = 4.34294481878168880939e-01; const ivln10lo: f64 = 2.50829467116452752298e-11; const log10_2hi: f64 = 3.01029995663611771306e-01; @@ -147,29 +150,29 @@ fn log10d(x_: f64) -> f64 { val_lo + val_hi } -test "log10" { - assert(log10(f32(0.2)) == log10f(0.2)); - assert(log10(f64(0.2)) == log10d(0.2)); +test "math.log10" { + assert(log10(f32(0.2)) == log10_32(0.2)); + assert(log10(f64(0.2)) == log10_64(0.2)); } -test "log10f" { +test "math.log10_32" { const epsilon = 0.000001; - assert(math.approxEq(f32, log10f(0.2), -0.698970, epsilon)); - assert(math.approxEq(f32, log10f(0.8923), -0.049489, epsilon)); - assert(math.approxEq(f32, log10f(1.5), 0.176091, epsilon)); - assert(math.approxEq(f32, log10f(37.45), 1.573452, epsilon)); - assert(math.approxEq(f32, log10f(89.123), 1.94999, epsilon)); - assert(math.approxEq(f32, log10f(123123.234375), 5.09034, epsilon)); + assert(math.approxEq(f32, log10_32(0.2), -0.698970, epsilon)); + assert(math.approxEq(f32, log10_32(0.8923), -0.049489, epsilon)); + assert(math.approxEq(f32, log10_32(1.5), 0.176091, epsilon)); + assert(math.approxEq(f32, log10_32(37.45), 1.573452, epsilon)); + assert(math.approxEq(f32, log10_32(89.123), 1.94999, epsilon)); + assert(math.approxEq(f32, log10_32(123123.234375), 5.09034, epsilon)); } -test "log10d" { +test "math.log10_64" { const epsilon = 0.000001; - assert(math.approxEq(f64, log10d(0.2), -0.698970, epsilon)); - assert(math.approxEq(f64, log10d(0.8923), -0.049489, epsilon)); - assert(math.approxEq(f64, log10d(1.5), 0.176091, epsilon)); - assert(math.approxEq(f64, log10d(37.45), 1.573452, epsilon)); - assert(math.approxEq(f64, log10d(89.123), 1.94999, epsilon)); - assert(math.approxEq(f64, log10d(123123.234375), 5.09034, epsilon)); + assert(math.approxEq(f64, log10_64(0.2), -0.698970, epsilon)); + assert(math.approxEq(f64, log10_64(0.8923), -0.049489, epsilon)); + assert(math.approxEq(f64, log10_64(1.5), 0.176091, epsilon)); + assert(math.approxEq(f64, log10_64(37.45), 1.573452, epsilon)); + assert(math.approxEq(f64, log10_64(89.123), 1.94999, epsilon)); + assert(math.approxEq(f64, log10_64(123123.234375), 5.09034, epsilon)); } diff --git a/std/math/log1p.zig b/std/math/log1p.zig index 811bd9e72..a4e96c76d 100644 --- a/std/math/log1p.zig +++ b/std/math/log1p.zig @@ -1,16 +1,19 @@ const math = @import("index.zig"); const assert = @import("../debug.zig").assert; -pub fn log1p(x: var) -> @typeOf(x) { +// TODO issue #393 +pub const log1p = log1p_workaround; + +pub fn log1p_workaround(x: var) -> @typeOf(x) { const T = @typeOf(x); switch (T) { - f32 => @inlineCall(log1pf, x), - f64 => @inlineCall(log1pd, x), + f32 => @inlineCall(log1p_32, x), + f64 => @inlineCall(log1p_64, x), else => @compileError("log1p not implemented for " ++ @typeName(T)), } } -fn log1pf(x: f32) -> f32 { +fn log1p_32(x: f32) -> f32 { const ln2_hi = 6.9313812256e-01; const ln2_lo = 9.0580006145e-06; const Lg1: f32 = 0xaaaaaa.0p-24; @@ -86,7 +89,7 @@ fn log1pf(x: f32) -> f32 { s * (hfsq + R) + (dk * ln2_lo + c) - hfsq + f + dk * ln2_hi } -fn log1pd(x: f64) -> f64 { +fn log1p_64(x: f64) -> f64 { const ln2_hi: f64 = 6.93147180369123816490e-01; const ln2_lo: f64 = 1.90821492927058770002e-10; const Lg1: f64 = 6.666666666666735130e-01; @@ -167,31 +170,31 @@ fn log1pd(x: f64) -> f64 { s * (hfsq + R) + (dk * ln2_lo + c) - hfsq + f + dk * ln2_hi } -test "log1p" { - assert(log1p(f32(0.0)) == log1pf(0.0)); - assert(log1p(f64(0.0)) == log1pd(0.0)); +test "math.log1p" { + assert(log1p(f32(0.0)) == log1p_32(0.0)); + assert(log1p(f64(0.0)) == log1p_64(0.0)); } -test "log1pf" { +test "math.log1p_32" { const epsilon = 0.000001; - assert(math.approxEq(f32, log1pf(0.0), 0.0, epsilon)); - assert(math.approxEq(f32, log1pf(0.2), 0.182322, epsilon)); - assert(math.approxEq(f32, log1pf(0.8923), 0.637793, epsilon)); - assert(math.approxEq(f32, log1pf(1.5), 0.916291, epsilon)); - assert(math.approxEq(f32, log1pf(37.45), 3.649359, epsilon)); - assert(math.approxEq(f32, log1pf(89.123), 4.501175, epsilon)); - assert(math.approxEq(f32, log1pf(123123.234375), 11.720949, epsilon)); + assert(math.approxEq(f32, log1p_32(0.0), 0.0, epsilon)); + assert(math.approxEq(f32, log1p_32(0.2), 0.182322, epsilon)); + assert(math.approxEq(f32, log1p_32(0.8923), 0.637793, epsilon)); + assert(math.approxEq(f32, log1p_32(1.5), 0.916291, epsilon)); + assert(math.approxEq(f32, log1p_32(37.45), 3.649359, epsilon)); + assert(math.approxEq(f32, log1p_32(89.123), 4.501175, epsilon)); + assert(math.approxEq(f32, log1p_32(123123.234375), 11.720949, epsilon)); } -test "log1pd" { +test "math.log1p_64" { const epsilon = 0.000001; - assert(math.approxEq(f64, log1pd(0.0), 0.0, epsilon)); - assert(math.approxEq(f64, log1pd(0.2), 0.182322, epsilon)); - assert(math.approxEq(f64, log1pd(0.8923), 0.637793, epsilon)); - assert(math.approxEq(f64, log1pd(1.5), 0.916291, epsilon)); - assert(math.approxEq(f64, log1pd(37.45), 3.649359, epsilon)); - assert(math.approxEq(f64, log1pd(89.123), 4.501175, epsilon)); - assert(math.approxEq(f64, log1pd(123123.234375), 11.720949, epsilon)); + assert(math.approxEq(f64, log1p_64(0.0), 0.0, epsilon)); + assert(math.approxEq(f64, log1p_64(0.2), 0.182322, epsilon)); + assert(math.approxEq(f64, log1p_64(0.8923), 0.637793, epsilon)); + assert(math.approxEq(f64, log1p_64(1.5), 0.916291, epsilon)); + assert(math.approxEq(f64, log1p_64(37.45), 3.649359, epsilon)); + assert(math.approxEq(f64, log1p_64(89.123), 4.501175, epsilon)); + assert(math.approxEq(f64, log1p_64(123123.234375), 11.720949, epsilon)); } diff --git a/std/math/log2.zig b/std/math/log2.zig index 67eb2c5e0..b4c7da5f0 100644 --- a/std/math/log2.zig +++ b/std/math/log2.zig @@ -1,16 +1,19 @@ const math = @import("index.zig"); const assert = @import("../debug.zig").assert; -pub fn log2(x: var) -> @typeOf(x) { +// TODO issue #393 +pub const log2 = log2_workaround; + +pub fn log2_workaround(x: var) -> @typeOf(x) { const T = @typeOf(x); switch (T) { - f32 => @inlineCall(log2f, x), - f64 => @inlineCall(log2d, x), + f32 => @inlineCall(log2_32, x), + f64 => @inlineCall(log2_64, x), else => @compileError("log2 not implemented for " ++ @typeName(T)), } } -fn log2f(x_: f32) -> f32 { +fn log2_32(x_: f32) -> f32 { const ivln2hi: f32 = 1.4428710938e+00; const ivln2lo: f32 = -1.7605285393e-04; const Lg1: f32 = 0xaaaaaa.0p-24; @@ -66,7 +69,7 @@ fn log2f(x_: f32) -> f32 { (lo + hi) * ivln2lo + lo * ivln2hi + hi * ivln2hi + f32(k) } -fn log2d(x_: f64) -> f64 { +fn log2_64(x_: f64) -> f64 { const ivln2hi: f64 = 1.44269504072144627571e+00; const ivln2lo: f64 = 1.67517131648865118353e-10; const Lg1: f64 = 6.666666666666735130e-01; @@ -139,27 +142,27 @@ fn log2d(x_: f64) -> f64 { val_lo + val_hi } -test "log2" { - assert(log2(f32(0.2)) == log2f(0.2)); - assert(log2(f64(0.2)) == log2d(0.2)); +test "math.log2" { + assert(log2(f32(0.2)) == log2_32(0.2)); + assert(log2(f64(0.2)) == log2_64(0.2)); } -test "log2f" { +test "math.log2_32" { const epsilon = 0.000001; - assert(math.approxEq(f32, log2f(0.2), -2.321928, epsilon)); - assert(math.approxEq(f32, log2f(0.8923), -0.164399, epsilon)); - assert(math.approxEq(f32, log2f(1.5), 0.584962, epsilon)); - assert(math.approxEq(f32, log2f(37.45), 5.226894, epsilon)); - assert(math.approxEq(f32, log2f(123123.234375), 16.909744, epsilon)); + assert(math.approxEq(f32, log2_32(0.2), -2.321928, epsilon)); + assert(math.approxEq(f32, log2_32(0.8923), -0.164399, epsilon)); + assert(math.approxEq(f32, log2_32(1.5), 0.584962, epsilon)); + assert(math.approxEq(f32, log2_32(37.45), 5.226894, epsilon)); + assert(math.approxEq(f32, log2_32(123123.234375), 16.909744, epsilon)); } -test "log2d" { +test "math.log2_64" { const epsilon = 0.000001; - assert(math.approxEq(f64, log2d(0.2), -2.321928, epsilon)); - assert(math.approxEq(f64, log2d(0.8923), -0.164399, epsilon)); - assert(math.approxEq(f64, log2d(1.5), 0.584962, epsilon)); - assert(math.approxEq(f64, log2d(37.45), 5.226894, epsilon)); - assert(math.approxEq(f64, log2d(123123.234375), 16.909744, epsilon)); + assert(math.approxEq(f64, log2_64(0.2), -2.321928, epsilon)); + assert(math.approxEq(f64, log2_64(0.8923), -0.164399, epsilon)); + assert(math.approxEq(f64, log2_64(1.5), 0.584962, epsilon)); + assert(math.approxEq(f64, log2_64(37.45), 5.226894, epsilon)); + assert(math.approxEq(f64, log2_64(123123.234375), 16.909744, epsilon)); } diff --git a/std/math/modf.zig b/std/math/modf.zig index 666fa04c8..3b9468b1a 100644 --- a/std/math/modf.zig +++ b/std/math/modf.zig @@ -1,6 +1,9 @@ const math = @import("index.zig"); const assert = @import("../debug.zig").assert; +// TODO issue #393 +pub const modf = modf_workaround; + fn modf_result(comptime T: type) -> type { struct { fpart: T, @@ -10,7 +13,7 @@ fn modf_result(comptime T: type) -> type { pub const modf32_result = modf_result(f32); pub const modf64_result = modf_result(f64); -pub fn modf(x: var) -> modf_result(@typeOf(x)) { +pub fn modf_workaround(x: var) -> modf_result(@typeOf(x)) { const T = @typeOf(x); switch (T) { f32 => @inlineCall(modf32, x), @@ -95,7 +98,7 @@ fn modf64(x: f64) -> modf64_result { result } -test "modf" { +test "math.modf" { const a = modf(f32(1.0)); const b = modf32(1.0); // NOTE: No struct comparison on generic return type function? non-named, makes sense, but still. @@ -106,7 +109,7 @@ test "modf" { assert(a.ipart == b.ipart and a.fpart == b.fpart); } -test "modf32" { +test "math.modf32" { const epsilon = 0.000001; var r: modf32_result = undefined; @@ -131,7 +134,7 @@ test "modf32" { assert(math.approxEq(f32, r.fpart, 0.340820, epsilon)); } -test "modf64" { +test "math.modf64" { const epsilon = 0.000001; var r: modf64_result = undefined; diff --git a/std/math/nan.zig b/std/math/nan.zig index bd079026a..7dc175a61 100644 --- a/std/math/nan.zig +++ b/std/math/nan.zig @@ -1,6 +1,8 @@ const math = @import("index.zig"); -pub fn nan(comptime T: type) -> T { +pub const nan = nan_workaround; + +pub fn nan_workaround(comptime T: type) -> T { switch (T) { f32 => @bitCast(f32, math.nan_u32), f64 => @bitCast(f64, math.nan_u64), diff --git a/std/math/oindex.zig b/std/math/oindex.zig deleted file mode 100644 index 312833249..000000000 --- a/std/math/oindex.zig +++ /dev/null @@ -1,274 +0,0 @@ -const assert = @import("../debug.zig").assert; -const builtin = @import("builtin"); - -pub const frexp = @import("frexp.zig").frexp; - -pub const Cmp = enum { - Less, - Equal, - Greater, -}; - -pub fn min(x: var, y: var) -> @typeOf(x + y) { - if (x < y) x else y -} - -test "math.min" { - assert(min(i32(-1), i32(2)) == -1); -} - -pub fn max(x: var, y: var) -> @typeOf(x + y) { - if (x > y) x else y -} - -test "math.max" { - assert(max(i32(-1), i32(2)) == 2); -} - -error Overflow; -pub fn mul(comptime T: type, a: T, b: T) -> %T { - var answer: T = undefined; - if (@mulWithOverflow(T, a, b, &answer)) error.Overflow else answer -} - -error Overflow; -pub fn add(comptime T: type, a: T, b: T) -> %T { - var answer: T = undefined; - if (@addWithOverflow(T, a, b, &answer)) error.Overflow else answer -} - -error Overflow; -pub fn sub(comptime T: type, a: T, b: T) -> %T { - var answer: T = undefined; - if (@subWithOverflow(T, a, b, &answer)) error.Overflow else answer -} - -pub fn negate(x: var) -> %@typeOf(x) { - return sub(@typeOf(x), 0, x); -} - -error Overflow; -pub fn shl(comptime T: type, a: T, b: T) -> %T { - var answer: T = undefined; - if (@shlWithOverflow(T, a, b, &answer)) error.Overflow else answer -} - -test "math overflow functions" { - testOverflow(); - comptime testOverflow(); -} - -fn testOverflow() { - assert(%%mul(i32, 3, 4) == 12); - assert(%%add(i32, 3, 4) == 7); - assert(%%sub(i32, 3, 4) == -1); - assert(%%shl(i32, 0b11, 4) == 0b110000); -} - - -error Overflow; -pub fn absInt(x: var) -> %@typeOf(x) { - const T = @typeOf(x); - comptime assert(@typeId(T) == builtin.TypeId.Int); // must pass an integer to absInt - comptime assert(T.is_signed); // must pass a signed integer to absInt - if (x == @minValue(@typeOf(x))) - return error.Overflow; - { - @setDebugSafety(this, false); - return if (x < 0) -x else x; - } -} - -test "math.absInt" { - testAbsInt(); - comptime testAbsInt(); -} -fn testAbsInt() { - assert(%%absInt(i32(-10)) == 10); - assert(%%absInt(i32(10)) == 10); -} - -pub const absFloat = @import("fabs.zig").fabs; - -error DivisionByZero; -error Overflow; -pub fn divTrunc(comptime T: type, numerator: T, denominator: T) -> %T { - @setDebugSafety(this, false); - if (denominator == 0) - return error.DivisionByZero; - if (@typeId(T) == builtin.TypeId.Int and T.is_signed and numerator == @minValue(T) and denominator == -1) - return error.Overflow; - return @divTrunc(numerator, denominator); -} - -test "math.divTrunc" { - testDivTrunc(); - comptime testDivTrunc(); -} -fn testDivTrunc() { - assert(%%divTrunc(i32, 5, 3) == 1); - assert(%%divTrunc(i32, -5, 3) == -1); - if (divTrunc(i8, -5, 0)) |_| unreachable else |err| assert(err == error.DivisionByZero); - if (divTrunc(i8, -128, -1)) |_| unreachable else |err| assert(err == error.Overflow); - - assert(%%divTrunc(f32, 5.0, 3.0) == 1.0); - assert(%%divTrunc(f32, -5.0, 3.0) == -1.0); -} - -error DivisionByZero; -error Overflow; -pub fn divFloor(comptime T: type, numerator: T, denominator: T) -> %T { - @setDebugSafety(this, false); - if (denominator == 0) - return error.DivisionByZero; - if (@typeId(T) == builtin.TypeId.Int and T.is_signed and numerator == @minValue(T) and denominator == -1) - return error.Overflow; - return @divFloor(numerator, denominator); -} - -test "math.divFloor" { - testDivFloor(); - comptime testDivFloor(); -} -fn testDivFloor() { - assert(%%divFloor(i32, 5, 3) == 1); - assert(%%divFloor(i32, -5, 3) == -2); - if (divFloor(i8, -5, 0)) |_| unreachable else |err| assert(err == error.DivisionByZero); - if (divFloor(i8, -128, -1)) |_| unreachable else |err| assert(err == error.Overflow); - - assert(%%divFloor(f32, 5.0, 3.0) == 1.0); - assert(%%divFloor(f32, -5.0, 3.0) == -2.0); -} - -error DivisionByZero; -error Overflow; -error UnexpectedRemainder; -pub fn divExact(comptime T: type, numerator: T, denominator: T) -> %T { - @setDebugSafety(this, false); - if (denominator == 0) - return error.DivisionByZero; - if (@typeId(T) == builtin.TypeId.Int and T.is_signed and numerator == @minValue(T) and denominator == -1) - return error.Overflow; - const result = @divTrunc(numerator, denominator); - if (result * denominator != numerator) - return error.UnexpectedRemainder; - return result; -} - -test "math.divExact" { - testDivExact(); - comptime testDivExact(); -} -fn testDivExact() { - assert(%%divExact(i32, 10, 5) == 2); - assert(%%divExact(i32, -10, 5) == -2); - if (divExact(i8, -5, 0)) |_| unreachable else |err| assert(err == error.DivisionByZero); - if (divExact(i8, -128, -1)) |_| unreachable else |err| assert(err == error.Overflow); - if (divExact(i32, 5, 2)) |_| unreachable else |err| assert(err == error.UnexpectedRemainder); - - assert(%%divExact(f32, 10.0, 5.0) == 2.0); - assert(%%divExact(f32, -10.0, 5.0) == -2.0); - if (divExact(f32, 5.0, 2.0)) |_| unreachable else |err| assert(err == error.UnexpectedRemainder); -} - -error DivisionByZero; -error NegativeDenominator; -pub fn mod(comptime T: type, numerator: T, denominator: T) -> %T { - @setDebugSafety(this, false); - if (denominator == 0) - return error.DivisionByZero; - if (denominator < 0) - return error.NegativeDenominator; - return @mod(numerator, denominator); -} - -test "math.mod" { - testMod(); - comptime testMod(); -} -fn testMod() { - assert(%%mod(i32, -5, 3) == 1); - assert(%%mod(i32, 5, 3) == 2); - if (mod(i32, 10, -1)) |_| unreachable else |err| assert(err == error.NegativeDenominator); - if (mod(i32, 10, 0)) |_| unreachable else |err| assert(err == error.DivisionByZero); - - assert(%%mod(f32, -5, 3) == 1); - assert(%%mod(f32, 5, 3) == 2); - if (mod(f32, 10, -1)) |_| unreachable else |err| assert(err == error.NegativeDenominator); - if (mod(f32, 10, 0)) |_| unreachable else |err| assert(err == error.DivisionByZero); -} - -error DivisionByZero; -error NegativeDenominator; -pub fn rem(comptime T: type, numerator: T, denominator: T) -> %T { - @setDebugSafety(this, false); - if (denominator == 0) - return error.DivisionByZero; - if (denominator < 0) - return error.NegativeDenominator; - return @rem(numerator, denominator); -} - -test "math.rem" { - testRem(); - comptime testRem(); -} -fn testRem() { - assert(%%rem(i32, -5, 3) == -2); - assert(%%rem(i32, 5, 3) == 2); - if (rem(i32, 10, -1)) |_| unreachable else |err| assert(err == error.NegativeDenominator); - if (rem(i32, 10, 0)) |_| unreachable else |err| assert(err == error.DivisionByZero); - - assert(%%rem(f32, -5, 3) == -2); - assert(%%rem(f32, 5, 3) == 2); - if (rem(f32, 10, -1)) |_| unreachable else |err| assert(err == error.NegativeDenominator); - if (rem(f32, 10, 0)) |_| unreachable else |err| assert(err == error.DivisionByZero); -} - -/// Returns the absolute value of the integer parameter. -/// Result is an unsigned integer. -pub fn absCast(x: var) -> @IntType(false, @typeOf(x).bit_count) { - const uint = @IntType(false, @typeOf(x).bit_count); - if (x >= 0) - return uint(x); - - return uint(-(x + 1)) + 1; -} - -test "math.absCast" { - assert(absCast(i32(-999)) == 999); - assert(@typeOf(absCast(i32(-999))) == u32); - - assert(absCast(i32(999)) == 999); - assert(@typeOf(absCast(i32(999))) == u32); - - assert(absCast(i32(@minValue(i32))) == -@minValue(i32)); - assert(@typeOf(absCast(i32(@minValue(i32)))) == u32); -} - -/// Returns the negation of the integer parameter. -/// Result is a signed integer. -error Overflow; -pub fn negateCast(x: var) -> %@IntType(true, @typeOf(x).bit_count) { - if (@typeOf(x).is_signed) - return negate(x); - - const int = @IntType(true, @typeOf(x).bit_count); - if (x > -@minValue(int)) - return error.Overflow; - - if (x == -@minValue(int)) - return @minValue(int); - - return -int(x); -} - -test "math.negateCast" { - assert(%%negateCast(u32(999)) == -999); - assert(@typeOf(%%negateCast(u32(999))) == i32); - - assert(%%negateCast(u32(-@minValue(i32))) == @minValue(i32)); - assert(@typeOf(%%negateCast(u32(-@minValue(i32)))) == i32); - - if (negateCast(u32(@maxValue(i32) + 10))) |_| unreachable else |err| assert(err == error.Overflow); -} diff --git a/std/math/pow.zig b/std/math/pow.zig index 007e6ed55..1252baf0d 100644 --- a/std/math/pow.zig +++ b/std/math/pow.zig @@ -1,8 +1,11 @@ const math = @import("index.zig"); const assert = @import("../debug.zig").assert; +// TODO issue #393 +pub const pow = pow_workaround; + // This implementation is taken from the go stlib, musl is a bit more complex. -pub fn pow(comptime T: type, x: T, y: T) -> T { +pub fn pow_workaround(comptime T: type, x: T, y: T) -> T { @setFloatMode(this, @import("builtin").FloatMode.Strict); @@ -158,9 +161,7 @@ test "math.pow" { assert(math.approxEq(f32, pow(f32, 0.2, 3.3), 0.004936, epsilon)); assert(math.approxEq(f32, pow(f32, 1.5, 3.3), 3.811546, epsilon)); assert(math.approxEq(f32, pow(f32, 37.45, 3.3), 155736.703125, epsilon)); - - // TODO: Determine why aborting on release mode. - // assert(math.approxEq(f32, pow(f32, 89.123, 3.3), 2722489.5, epsilon)); + assert(math.approxEq(f32, pow(f32, 89.123, 3.3), 2722489.5, epsilon)); // assert(math.approxEq(f32, pow(f64, 0.0, 3.3), 0.0, epsilon)); // TODO: Handle div zero assert(math.approxEq(f64, pow(f64, 0.8923, 3.3), 0.686572, epsilon)); diff --git a/std/math/round.zig b/std/math/round.zig index 41768b7ba..dfdce3db9 100644 --- a/std/math/round.zig +++ b/std/math/round.zig @@ -2,7 +2,10 @@ const builtin = @import("builtin"); const assert = @import("../debug.zig").assert; const math = @import("index.zig"); -pub fn round(x: var) -> @typeOf(x) { +// TODO issue #393 +pub const round = round_workaround; + +pub fn round_workaround(x: var) -> @typeOf(x) { const T = @typeOf(x); switch (T) { f32 => @inlineCall(round32, x), @@ -85,19 +88,19 @@ fn round64(x_: f64) -> f64 { } } -test "round" { +test "math.round" { assert(round(f32(1.3)) == round32(1.3)); assert(round(f64(1.3)) == round64(1.3)); } -test "round32" { +test "math.round32" { assert(round32(1.3) == 1.0); assert(round32(-1.3) == -1.0); assert(round32(0.2) == 0.0); assert(round32(1.8) == 2.0); } -test "round64" { +test "math.round64" { assert(round64(1.3) == 1.0); assert(round64(-1.3) == -1.0); assert(round64(0.2) == 0.0); diff --git a/std/math/scalbn.zig b/std/math/scalbn.zig index b0b207e9d..10ca57d99 100644 --- a/std/math/scalbn.zig +++ b/std/math/scalbn.zig @@ -1,7 +1,10 @@ const math = @import("index.zig"); const assert = @import("../debug.zig").assert; -pub fn scalbn(x: var, n: i32) -> @typeOf(x) { +// TODO issue #393 +pub const scalbn = scalbn_workaround; + +pub fn scalbn_workaround(x: var, n: i32) -> @typeOf(x) { const T = @typeOf(x); switch (T) { f32 => @inlineCall(scalbn32, x, n), @@ -71,15 +74,15 @@ fn scalbn64(x: f64, n_: i32) -> f64 { y * @bitCast(f64, u) } -test "scalbn" { +test "math.scalbn" { assert(scalbn(f32(1.5), 4) == scalbn32(1.5, 4)); assert(scalbn(f64(1.5), 4) == scalbn64(1.5, 4)); } -test "scalbn32" { +test "math.scalbn32" { assert(scalbn32(1.5, 4) == 24.0); } -test "scalbn64" { +test "math.scalbn64" { assert(scalbn64(1.5, 4) == 24.0); } diff --git a/std/math/signbit.zig b/std/math/signbit.zig index fcc7224a8..979c45bf4 100644 --- a/std/math/signbit.zig +++ b/std/math/signbit.zig @@ -1,7 +1,10 @@ const math = @import("index.zig"); const assert = @import("../debug.zig").assert; -pub fn signbit(x: var) -> bool { +// TODO issue #393 +pub const signbit = signbit_workaround; + +pub fn signbit_workaround(x: var) -> bool { const T = @typeOf(x); switch (T) { f32 => @inlineCall(signbit32, x), @@ -20,17 +23,17 @@ fn signbit64(x: f64) -> bool { bits >> 63 != 0 } -test "signbit" { +test "math.signbit" { assert(signbit(f32(4.0)) == signbit32(4.0)); assert(signbit(f64(4.0)) == signbit64(4.0)); } -test "signbit32" { +test "math.signbit32" { assert(!signbit32(4.0)); assert(signbit32(-3.0)); } -test "signbit64" { +test "math.signbit64" { assert(!signbit64(4.0)); assert(signbit64(-3.0)); } diff --git a/std/math/sin.zig b/std/math/sin.zig index e3a14898f..a1b6c3cad 100644 --- a/std/math/sin.zig +++ b/std/math/sin.zig @@ -1,7 +1,10 @@ const math = @import("index.zig"); const assert = @import("../debug.zig").assert; -pub fn sin(x: var) -> @typeOf(x) { +// TODO issue #393 +pub const sin = sin_workaround; + +pub fn sin_workaround(x: var) -> @typeOf(x) { const T = @typeOf(x); switch (T) { f32 => @inlineCall(sin32, x), @@ -135,12 +138,12 @@ fn sin64(x_: f64) -> f64 { } } -test "sin" { +test "math.sin" { assert(sin(f32(0.0)) == sin32(0.0)); assert(sin(f64(0.0)) == sin64(0.0)); } -test "sin32" { +test "math.sin32" { const epsilon = 0.000001; assert(math.approxEq(f32, sin32(0.0), 0.0, epsilon)); @@ -151,7 +154,7 @@ test "sin32" { assert(math.approxEq(f32, sin32(89.123), 0.916166, epsilon)); } -test "sin64" { +test "math.sin64" { const epsilon = 0.000001; assert(math.approxEq(f64, sin64(0.0), 0.0, epsilon)); diff --git a/std/math/sinh.zig b/std/math/sinh.zig index 7535bc2b5..01590c4b1 100644 --- a/std/math/sinh.zig +++ b/std/math/sinh.zig @@ -2,11 +2,14 @@ const math = @import("index.zig"); const assert = @import("../debug.zig").assert; const expo2 = @import("_expo2.zig").expo2; -pub fn sinh(x: var) -> @typeOf(x) { +// TODO issue #393 +pub const sinh = sinh_workaround; + +pub fn sinh_workaround(x: var) -> @typeOf(x) { const T = @typeOf(x); switch (T) { - f32 => @inlineCall(sinhf, x), - f64 => @inlineCall(sinhd, x), + f32 => @inlineCall(sinh32, x), + f64 => @inlineCall(sinh64, x), else => @compileError("sinh not implemented for " ++ @typeName(T)), } } @@ -14,7 +17,7 @@ pub fn sinh(x: var) -> @typeOf(x) { // sinh(x) = (exp(x) - 1 / exp(x)) / 2 // = (exp(x) - 1 + (exp(x) - 1) / exp(x)) / 2 // = x + x^3 / 6 + o(x^5) -fn sinhf(x: f32) -> f32 { +fn sinh32(x: f32) -> f32 { const u = @bitCast(u32, x); const ux = u & 0x7FFFFFFF; const ax = @bitCast(f32, ux); @@ -41,7 +44,7 @@ fn sinhf(x: f32) -> f32 { 2 * h * expo2(ax) } -fn sinhd(x: f64) -> f64 { +fn sinh64(x: f64) -> f64 { const u = @bitCast(u64, x); const w = u32(u >> 32); const ax = @bitCast(f64, u & (@maxValue(u64) >> 1)); @@ -69,25 +72,25 @@ fn sinhd(x: f64) -> f64 { 2 * h * expo2(ax) } -test "sinh" { - assert(sinh(f32(1.5)) == sinhf(1.5)); - assert(sinh(f64(1.5)) == sinhd(1.5)); +test "math.sinh" { + assert(sinh(f32(1.5)) == sinh32(1.5)); + assert(sinh(f64(1.5)) == sinh64(1.5)); } -test "sinhf" { +test "math.sinh32" { const epsilon = 0.000001; - assert(math.approxEq(f32, sinhf(0.0), 0.0, epsilon)); - assert(math.approxEq(f32, sinhf(0.2), 0.201336, epsilon)); - assert(math.approxEq(f32, sinhf(0.8923), 1.015512, epsilon)); - assert(math.approxEq(f32, sinhf(1.5), 2.129279, epsilon)); + assert(math.approxEq(f32, sinh32(0.0), 0.0, epsilon)); + assert(math.approxEq(f32, sinh32(0.2), 0.201336, epsilon)); + assert(math.approxEq(f32, sinh32(0.8923), 1.015512, epsilon)); + assert(math.approxEq(f32, sinh32(1.5), 2.129279, epsilon)); } -test "sinhd" { +test "math.sinh64" { const epsilon = 0.000001; - assert(math.approxEq(f64, sinhd(0.0), 0.0, epsilon)); - assert(math.approxEq(f64, sinhd(0.2), 0.201336, epsilon)); - assert(math.approxEq(f64, sinhd(0.8923), 1.015512, epsilon)); - assert(math.approxEq(f64, sinhd(1.5), 2.129279, epsilon)); + assert(math.approxEq(f64, sinh64(0.0), 0.0, epsilon)); + assert(math.approxEq(f64, sinh64(0.2), 0.201336, epsilon)); + assert(math.approxEq(f64, sinh64(0.8923), 1.015512, epsilon)); + assert(math.approxEq(f64, sinh64(1.5), 2.129279, epsilon)); } diff --git a/std/math/sqrt.zig b/std/math/sqrt.zig index f47a5972c..1257c0cf6 100644 --- a/std/math/sqrt.zig +++ b/std/math/sqrt.zig @@ -1,7 +1,10 @@ const math = @import("index.zig"); const assert = @import("../debug.zig").assert; -pub fn sqrt(x: var) -> @typeOf(x) { +// TODO issue #393 +pub const sqrt = sqrt_workaround; + +pub fn sqrt_workaround(x: var) -> @typeOf(x) { const T = @typeOf(x); switch (T) { f32 => @inlineCall(sqrt32, x), @@ -219,12 +222,12 @@ fn sqrt64(x: f64) -> f64 { @bitCast(f64, uz) } -test "sqrt" { +test "math.sqrt" { assert(sqrt(f32(0.0)) == sqrt32(0.0)); assert(sqrt(f64(0.0)) == sqrt64(0.0)); } -test "sqrt32" { +test "math.sqrt32" { const epsilon = 0.000001; assert(sqrt32(0.0) == 0.0); @@ -238,7 +241,7 @@ test "sqrt32" { assert(math.approxEq(f32, sqrt32(8942.230469), 94.563370, epsilon)); } -test "sqrt64" { +test "math.sqrt64" { const epsilon = 0.000001; assert(sqrt64(0.0) == 0.0); diff --git a/std/math/tan.zig b/std/math/tan.zig index 6c86f9b38..a2b7fddfa 100644 --- a/std/math/tan.zig +++ b/std/math/tan.zig @@ -1,7 +1,9 @@ const math = @import("index.zig"); const assert = @import("../debug.zig").assert; -pub fn tan(x: var) -> @typeOf(x) { +pub const tan = tan_workaround; + +pub fn tan_workaround(x: var) -> @typeOf(x) { const T = @typeOf(x); switch (T) { f32 => @inlineCall(tan32, x), @@ -122,12 +124,12 @@ fn tan64(x_: f64) -> f64 { r } -test "tan" { +test "math.tan" { assert(tan(f32(0.0)) == tan32(0.0)); assert(tan(f64(0.0)) == tan64(0.0)); } -test "tan32" { +test "math.tan32" { const epsilon = 0.000001; assert(math.approxEq(f32, tan32(0.0), 0.0, epsilon)); @@ -138,7 +140,7 @@ test "tan32" { assert(math.approxEq(f32, tan32(89.123), 2.285852, epsilon)); } -test "tan64" { +test "math.tan64" { const epsilon = 0.000001; assert(math.approxEq(f64, tan64(0.0), 0.0, epsilon)); diff --git a/std/math/tanh.zig b/std/math/tanh.zig index 6f64a7ef8..bf4d86f7e 100644 --- a/std/math/tanh.zig +++ b/std/math/tanh.zig @@ -2,11 +2,14 @@ const math = @import("index.zig"); const assert = @import("../debug.zig").assert; const expo2 = @import("_expo2.zig").expo2; -pub fn tanh(x: var) -> @typeOf(x) { +// TODO issue #393 +pub const tanh = tanh_workaround; + +pub fn tanh_workaround(x: var) -> @typeOf(x) { const T = @typeOf(x); switch (T) { - f32 => @inlineCall(tanhf, x), - f64 => @inlineCall(tanhd, x), + f32 => @inlineCall(tanh32, x), + f64 => @inlineCall(tanh64, x), else => @compileError("tanh not implemented for " ++ @typeName(T)), } } @@ -14,7 +17,7 @@ pub fn tanh(x: var) -> @typeOf(x) { // tanh(x) = (exp(x) - exp(-x)) / (exp(x) + exp(-x)) // = (exp(2x) - 1) / (exp(2x) - 1 + 2) // = (1 - exp(-2x)) / (exp(-2x) - 1 + 2) -fn tanhf(x: f32) -> f32 { +fn tanh32(x: f32) -> f32 { const u = @bitCast(u32, x); const ux = u & 0x7FFFFFFF; const ax = @bitCast(f32, ux); @@ -54,7 +57,7 @@ fn tanhf(x: f32) -> f32 { } } -fn tanhd(x: f64) -> f64 { +fn tanh64(x: f64) -> f64 { const u = @bitCast(u64, x); const w = u32(u >> 32); const ax = @bitCast(f64, u & (@maxValue(u64) >> 1)); @@ -94,27 +97,27 @@ fn tanhd(x: f64) -> f64 { } } -test "tanh" { - assert(tanh(f32(1.5)) == tanhf(1.5)); - assert(tanh(f64(1.5)) == tanhd(1.5)); +test "math.tanh" { + assert(tanh(f32(1.5)) == tanh32(1.5)); + assert(tanh(f64(1.5)) == tanh64(1.5)); } -test "tanhf" { +test "math.tanh32" { const epsilon = 0.000001; - assert(math.approxEq(f32, tanhf(0.0), 0.0, epsilon)); - assert(math.approxEq(f32, tanhf(0.2), 0.197375, epsilon)); - assert(math.approxEq(f32, tanhf(0.8923), 0.712528, epsilon)); - assert(math.approxEq(f32, tanhf(1.5), 0.905148, epsilon)); - assert(math.approxEq(f32, tanhf(37.45), 1.0, epsilon)); + assert(math.approxEq(f32, tanh32(0.0), 0.0, epsilon)); + assert(math.approxEq(f32, tanh32(0.2), 0.197375, epsilon)); + assert(math.approxEq(f32, tanh32(0.8923), 0.712528, epsilon)); + assert(math.approxEq(f32, tanh32(1.5), 0.905148, epsilon)); + assert(math.approxEq(f32, tanh32(37.45), 1.0, epsilon)); } -test "tanhd" { +test "math.tanh64" { const epsilon = 0.000001; - assert(math.approxEq(f64, tanhd(0.0), 0.0, epsilon)); - assert(math.approxEq(f64, tanhd(0.2), 0.197375, epsilon)); - assert(math.approxEq(f64, tanhd(0.8923), 0.712528, epsilon)); - assert(math.approxEq(f64, tanhd(1.5), 0.905148, epsilon)); - assert(math.approxEq(f64, tanhd(37.45), 1.0, epsilon)); + assert(math.approxEq(f64, tanh64(0.0), 0.0, epsilon)); + assert(math.approxEq(f64, tanh64(0.2), 0.197375, epsilon)); + assert(math.approxEq(f64, tanh64(0.8923), 0.712528, epsilon)); + assert(math.approxEq(f64, tanh64(1.5), 0.905148, epsilon)); + assert(math.approxEq(f64, tanh64(37.45), 1.0, epsilon)); } diff --git a/std/math/trunc.zig b/std/math/trunc.zig index 8c2c1b049..7311da2f1 100644 --- a/std/math/trunc.zig +++ b/std/math/trunc.zig @@ -1,7 +1,9 @@ const math = @import("index.zig"); const assert = @import("../debug.zig").assert; -pub fn trunc(x: var) -> @typeOf(x) { +pub const trunc = trunc_workaround; + +pub fn trunc_workaround(x: var) -> @typeOf(x) { const T = @typeOf(x); switch (T) { f32 => @inlineCall(trunc32, x), @@ -52,18 +54,18 @@ fn trunc64(x: f64) -> f64 { } } -test "trunc" { +test "math.trunc" { assert(trunc(f32(1.3)) == trunc32(1.3)); assert(trunc(f64(1.3)) == trunc64(1.3)); } -test "trunc32" { +test "math.trunc32" { assert(trunc32(1.3) == 1.0); assert(trunc32(-1.3) == -1.0); assert(trunc32(0.2) == 0.0); } -test "trunc64" { +test "math.trunc64" { assert(trunc64(1.3) == 1.0); assert(trunc64(-1.3) == -1.0); assert(trunc64(0.2) == 0.0);