workaround for llvm bug

See #393 for details
This commit is contained in:
Andrew Kelley 2017-06-19 14:36:33 -04:00
parent 799c699101
commit c9fc8bd802
46 changed files with 479 additions and 846 deletions

View File

@ -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);

View File

@ -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));

View File

@ -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));
}

View File

@ -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));

View File

@ -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));
}

View File

@ -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));

View File

@ -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));
}

View File

@ -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));
}

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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));

View File

@ -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));
}

View File

@ -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);

View File

@ -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));
}

View File

@ -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));
}

View File

@ -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);
}

View File

@ -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);

View File

@ -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));

View File

@ -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));
}

View File

@ -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;

View File

@ -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));

View File

@ -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);

View File

@ -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");

View File

@ -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)));

View File

@ -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)));

View File

@ -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)));

View File

@ -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)));

View File

@ -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),

View File

@ -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)));

View File

@ -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));
}

View File

@ -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));
}

View File

@ -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));
}

View File

@ -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;

View File

@ -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),

View File

@ -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);
}

View File

@ -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));

View File

@ -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);

View File

@ -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);
}

View File

@ -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));
}

View File

@ -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));

View File

@ -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));
}

View File

@ -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);

View File

@ -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));

View File

@ -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));
}

View File

@ -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);