Merge pull request #20069 from LewisGaul/math-tests-simplified

Math tests simplified (exp and log functions) with bugfixes
This commit is contained in:
Andrew Kelley 2025-07-17 18:44:51 +02:00 committed by GitHub
commit a35688b613
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 497 additions and 210 deletions

View file

@ -10,6 +10,7 @@ const arch = builtin.cpu.arch;
const math = std.math;
const mem = std.mem;
const expect = std.testing.expect;
const expectEqual = std.testing.expectEqual;
const common = @import("common.zig");
pub const panic = common.panic;
@ -211,32 +212,100 @@ pub fn expl(x: c_longdouble) callconv(.c) c_longdouble {
}
}
test "exp32" {
const epsilon = 0.000001;
try expect(expf(0.0) == 1.0);
try expect(math.approxEqAbs(f32, expf(0.0), 1.0, epsilon));
try expect(math.approxEqAbs(f32, expf(0.2), 1.221403, epsilon));
try expect(math.approxEqAbs(f32, expf(0.8923), 2.440737, epsilon));
try expect(math.approxEqAbs(f32, expf(1.5), 4.481689, epsilon));
}
test "exp64" {
const epsilon = 0.000001;
try expect(exp(0.0) == 1.0);
try expect(math.approxEqAbs(f64, exp(0.0), 1.0, epsilon));
try expect(math.approxEqAbs(f64, exp(0.2), 1.221403, epsilon));
try expect(math.approxEqAbs(f64, exp(0.8923), 2.440737, epsilon));
try expect(math.approxEqAbs(f64, exp(1.5), 4.481689, epsilon));
}
test "exp32.special" {
try expect(math.isPositiveInf(expf(math.inf(f32))));
test "expf() special" {
try expectEqual(expf(0.0), 1.0);
try expectEqual(expf(-0.0), 1.0);
try expectEqual(expf(1.0), math.e);
try expectEqual(expf(math.ln2), 2.0);
try expectEqual(expf(math.inf(f32)), math.inf(f32));
try expect(math.isPositiveZero(expf(-math.inf(f32))));
try expect(math.isNan(expf(math.nan(f32))));
try expect(math.isNan(expf(math.snan(f32))));
}
test "exp64.special" {
try expect(math.isPositiveInf(exp(math.inf(f64))));
try expect(math.isNan(exp(math.nan(f64))));
test "expf() sanity" {
try expectEqual(expf(-0x1.0223a0p+3), 0x1.490320p-12);
try expectEqual(expf(0x1.161868p+2), 0x1.34712ap+6);
try expectEqual(expf(-0x1.0c34b4p+3), 0x1.e06b1ap-13);
try expectEqual(expf(-0x1.a206f0p+2), 0x1.7dd484p-10);
try expectEqual(expf(0x1.288bbcp+3), 0x1.4abc80p+13);
try expectEqual(expf(0x1.52efd0p-1), 0x1.f04a9cp+0);
try expectEqual(expf(-0x1.a05cc8p-2), 0x1.54f1e0p-1);
try expectEqual(expf(0x1.1f9efap-1), 0x1.c0f628p+0);
try expectEqual(expf(0x1.8c5db0p-1), 0x1.1599b2p+1);
try expectEqual(expf(-0x1.5b86eap-1), 0x1.03b572p-1);
try expectEqual(expf(-0x1.57f25cp+2), 0x1.2fbea2p-8);
try expectEqual(expf(0x1.c7d310p+3), 0x1.76eefp+20);
try expectEqual(expf(0x1.19be70p+4), 0x1.52d3dep+25);
try expectEqual(expf(-0x1.ab6d70p+3), 0x1.a88adep-20);
try expectEqual(expf(-0x1.5ac18ep+2), 0x1.22b328p-8);
try expectEqual(expf(-0x1.925982p-1), 0x1.d2acc0p-2);
try expectEqual(expf(0x1.7221cep+3), 0x1.9c2ceap+16);
try expectEqual(expf(0x1.11a0d4p+4), 0x1.980ee6p+24);
try expectEqual(expf(-0x1.ae41a2p+1), 0x1.1c28d0p-5);
try expectEqual(expf(-0x1.329154p+4), 0x1.47ef94p-28);
}
test "expf() boundary" {
try expectEqual(expf(0x1.62e42ep+6), 0x1.ffff08p+127); // The last value before the result gets infinite
try expectEqual(expf(0x1.62e430p+6), math.inf(f32)); // The first value that gives inf
try expectEqual(expf(0x1.fffffep+127), math.inf(f32)); // Max input value
try expectEqual(expf(0x1p-149), 1.0); // Min positive input value
try expectEqual(expf(-0x1p-149), 1.0); // Min negative input value
try expectEqual(expf(0x1p-126), 1.0); // First positive subnormal input
try expectEqual(expf(-0x1p-126), 1.0); // First negative subnormal input
try expectEqual(expf(-0x1.9fe368p+6), 0x1p-149); // The last value before the result flushes to zero
try expectEqual(expf(-0x1.9fe36ap+6), 0.0); // The first value at which the result flushes to zero
try expectEqual(expf(-0x1.5d589ep+6), 0x1.00004cp-126); // The last value before the result flushes to subnormal
try expectEqual(expf(-0x1.5d58a0p+6), 0x1.ffff98p-127); // The first value for which the result flushes to subnormal
}
test "exp() special" {
try expectEqual(exp(0.0), 1.0);
try expectEqual(exp(-0.0), 1.0);
// TODO: Accuracy error - off in the last bit in 64-bit, disagreeing with GCC
// try expectEqual(exp(1.0), math.e);
try expectEqual(exp(math.ln2), 2.0);
try expectEqual(exp(math.inf(f64)), math.inf(f64));
try expect(math.isPositiveZero(exp(-math.inf(f64))));
try expect(math.isNan(exp(math.nan(f64))));
try expect(math.isNan(exp(math.snan(f64))));
}
test "exp() sanity" {
try expectEqual(exp(-0x1.02239f3c6a8f1p+3), 0x1.490327ea61235p-12);
try expectEqual(exp(0x1.161868e18bc67p+2), 0x1.34712ed238c04p+6);
try expectEqual(exp(-0x1.0c34b3e01e6e7p+3), 0x1.e06b1b6c18e64p-13);
try expectEqual(exp(-0x1.a206f0a19dcc4p+2), 0x1.7dd47f810e68cp-10);
try expectEqual(exp(0x1.288bbb0d6a1e6p+3), 0x1.4abc77496e07ep+13);
try expectEqual(exp(0x1.52efd0cd80497p-1), 0x1.f04a9c1080500p+0);
try expectEqual(exp(-0x1.a05cc754481d1p-2), 0x1.54f1e0fd3ea0dp-1);
try expectEqual(exp(0x1.1f9ef934745cbp-1), 0x1.c0f6266a6a547p+0);
try expectEqual(exp(0x1.8c5db097f7442p-1), 0x1.1599b1d4a25fbp+1);
try expectEqual(exp(-0x1.5b86ea8118a0ep-1), 0x1.03b5728a00229p-1);
try expectEqual(exp(-0x1.57f25b2b5006dp+2), 0x1.2fbea6a01cab9p-8);
try expectEqual(exp(0x1.c7d30fb825911p+3), 0x1.76eeed45a0634p+20);
try expectEqual(exp(0x1.19be709de7505p+4), 0x1.52d3eb7be6844p+25);
try expectEqual(exp(-0x1.ab6d6fba96889p+3), 0x1.a88ae12f985d6p-20);
try expectEqual(exp(-0x1.5ac18e27084ddp+2), 0x1.22b327da9cca6p-8);
try expectEqual(exp(-0x1.925981b093c41p-1), 0x1.d2acc046b55f7p-2);
try expectEqual(exp(0x1.7221cd18455f5p+3), 0x1.9c2cde8699cfbp+16);
try expectEqual(exp(0x1.11a0d4a51b239p+4), 0x1.980ef612ff182p+24);
try expectEqual(exp(-0x1.ae41a1079de4dp+1), 0x1.1c28d16bb3222p-5);
try expectEqual(exp(-0x1.329153103b871p+4), 0x1.47efa6ddd0d22p-28);
}
test "exp() boundary" {
try expectEqual(exp(0x1.62e42fefa39efp+9), 0x1.fffffffffff2ap+1023); // The last value before the result gets infinite
try expectEqual(exp(0x1.62e42fefa39f0p+9), math.inf(f64)); // The first value that gives inf
try expectEqual(exp(0x1.fffffffffffffp+1023), math.inf(f64)); // Max input value
try expectEqual(exp(0x1p-1074), 1.0); // Min positive input value
try expectEqual(exp(-0x1p-1074), 1.0); // Min negative input value
try expectEqual(exp(0x1p-1022), 1.0); // First positive subnormal input
try expectEqual(exp(-0x1p-1022), 1.0); // First negative subnormal input
try expectEqual(exp(-0x1.74910d52d3051p+9), 0x1p-1074); // The last value before the result flushes to zero
try expectEqual(exp(-0x1.74910d52d3052p+9), 0.0); // The first value at which the result flushes to zero
try expectEqual(exp(-0x1.6232bdd7abcd2p+9), 0x1.000000000007cp-1022); // The last value before the result flushes to subnormal
try expectEqual(exp(-0x1.6232bdd7abcd3p+9), 0x1.ffffffffffcf8p-1023); // The first value for which the result flushes to subnormal
}

View file

@ -10,6 +10,7 @@ const arch = builtin.cpu.arch;
const math = std.math;
const mem = std.mem;
const expect = std.testing.expect;
const expectEqual = std.testing.expectEqual;
const common = @import("common.zig");
pub const panic = common.panic;
@ -58,7 +59,7 @@ pub fn exp2f(x: f32) callconv(.c) f32 {
if (common.want_float_exceptions) mem.doNotOptimizeAway(-0x1.0p-149 / x);
}
// x <= -150
if (u >= 0x3160000) {
if (u >= 0xC3160000) {
return 0;
}
}
@ -457,34 +458,78 @@ const exp2dt = [_]f64{
0x1.690f4b19e9471p+0, -0x1.9780p-45,
};
test "exp2_32" {
const epsilon = 0.000001;
try expect(exp2f(0.0) == 1.0);
try expect(math.approxEqAbs(f32, exp2f(0.2), 1.148698, epsilon));
try expect(math.approxEqAbs(f32, exp2f(0.8923), 1.856133, epsilon));
try expect(math.approxEqAbs(f32, exp2f(1.5), 2.828427, epsilon));
try expect(math.approxEqAbs(f32, exp2f(37.45), 187747237888, epsilon));
try expect(math.approxEqAbs(f32, exp2f(-1), 0.5, epsilon));
}
test "exp2_64" {
const epsilon = 0.000001;
try expect(exp2(0.0) == 1.0);
try expect(math.approxEqAbs(f64, exp2(0.2), 1.148698, epsilon));
try expect(math.approxEqAbs(f64, exp2(0.8923), 1.856133, epsilon));
try expect(math.approxEqAbs(f64, exp2(1.5), 2.828427, epsilon));
try expect(math.approxEqAbs(f64, exp2(-1), 0.5, epsilon));
try expect(math.approxEqAbs(f64, exp2(-0x1.a05cc754481d1p-2), 0x1.824056efc687cp-1, epsilon));
}
test "exp2_32.special" {
try expect(math.isPositiveInf(exp2f(math.inf(f32))));
test "exp2f() special" {
try expectEqual(exp2f(0.0), 1.0);
try expectEqual(exp2f(-0.0), 1.0);
try expectEqual(exp2f(1.0), 2.0);
try expectEqual(exp2f(-1.0), 0.5);
try expectEqual(exp2f(math.inf(f32)), math.inf(f32));
try expect(math.isPositiveZero(exp2f(-math.inf(f32))));
try expect(math.isNan(exp2f(math.nan(f32))));
try expect(math.isNan(exp2f(math.snan(f32))));
}
test "exp2_64.special" {
try expect(math.isPositiveInf(exp2(math.inf(f64))));
try expect(math.isNan(exp2(math.nan(f64))));
test "exp2f() sanity" {
try expectEqual(exp2f(-0x1.0223a0p+3), 0x1.e8d134p-9);
try expectEqual(exp2f(0x1.161868p+2), 0x1.453672p+4);
try expectEqual(exp2f(-0x1.0c34b4p+3), 0x1.890ca0p-9);
try expectEqual(exp2f(-0x1.a206f0p+2), 0x1.622d4ep-7);
try expectEqual(exp2f(0x1.288bbcp+3), 0x1.340ecep+9);
try expectEqual(exp2f(0x1.52efd0p-1), 0x1.950eeep+0);
try expectEqual(exp2f(-0x1.a05cc8p-2), 0x1.824056p-1);
try expectEqual(exp2f(0x1.1f9efap-1), 0x1.79dfa2p+0);
try expectEqual(exp2f(0x1.8c5db0p-1), 0x1.b5ceacp+0);
try expectEqual(exp2f(-0x1.5b86eap-1), 0x1.3fd8bap-1);
}
test "exp2f() boundary" {
try expectEqual(exp2f(0x1.fffffep+6), 0x1.ffff4ep+127); // The last value before the result gets infinite
try expectEqual(exp2f(0x1p+7), math.inf(f32)); // The first value that gives infinite result
try expectEqual(exp2f(-0x1.2bccccp+7), 0x1p-149); // The last value before the result flushes to zero
try expectEqual(exp2f(-0x1.2cp+7), 0); // The first value at which the result flushes to zero
try expectEqual(exp2f(-0x1.f8p+6), 0x1p-126); // The last value before the result flushes to subnormal
try expectEqual(exp2f(-0x1.f80002p+6), 0x1.ffff50p-127); // The first value for which the result flushes to subnormal
try expectEqual(exp2f(0x1.fffffep+127), math.inf(f32)); // Max input value
try expectEqual(exp2f(0x1p-149), 1); // Min positive input value
try expectEqual(exp2f(-0x1p-149), 1); // Min negative input value
try expectEqual(exp2f(0x1p-126), 1); // First positive subnormal input
try expectEqual(exp2f(-0x1p-126), 1); // First negative subnormal input
}
test "exp2() special" {
try expectEqual(exp2(0.0), 1.0);
try expectEqual(exp2(-0.0), 1.0);
try expectEqual(exp2(1.0), 2.0);
try expectEqual(exp2(-1.0), 0.5);
try expectEqual(exp2(math.inf(f64)), math.inf(f64));
try expect(math.isPositiveZero(exp2(-math.inf(f64))));
try expect(math.isNan(exp2(math.nan(f64))));
try expect(math.isNan(exp2(math.snan(f64))));
}
test "exp2() sanity" {
try expectEqual(exp2(-0x1.02239f3c6a8f1p+3), 0x1.e8d13c396f452p-9);
try expectEqual(exp2(0x1.161868e18bc67p+2), 0x1.4536746bb6f12p+4);
try expectEqual(exp2(-0x1.0c34b3e01e6e7p+3), 0x1.890ca0c00b9a2p-9);
try expectEqual(exp2(-0x1.a206f0a19dcc4p+2), 0x1.622d4b0ebc6c1p-7);
try expectEqual(exp2(0x1.288bbb0d6a1e6p+3), 0x1.340ec7f3e607ep+9);
try expectEqual(exp2(0x1.52efd0cd80497p-1), 0x1.950eef4bc5451p+0);
try expectEqual(exp2(-0x1.a05cc754481d1p-2), 0x1.824056efc687cp-1);
try expectEqual(exp2(0x1.1f9ef934745cbp-1), 0x1.79dfa14ab121ep+0);
try expectEqual(exp2(0x1.8c5db097f7442p-1), 0x1.b5cead2247372p+0);
try expectEqual(exp2(-0x1.5b86ea8118a0ep-1), 0x1.3fd8ba33216b9p-1);
}
test "exp2() boundary" {
try expectEqual(exp2(0x1.fffffffffffffp+9), 0x1.ffffffffffd3ap+1023); // The last value before the result gets infinite
try expectEqual(exp2(0x1p+10), math.inf(f64)); // The first value that gives infinite result
try expectEqual(exp2(-0x1.0cbffffffffffp+10), 0x1p-1074); // The last value before the result flushes to zero
try expectEqual(exp2(-0x1.0ccp+10), 0); // The first value at which the result flushes to zero
try expectEqual(exp2(-0x1.ffp+9), 0x1p-1022); // The last value before the result flushes to subnormal
try expectEqual(exp2(-0x1.ff00000000001p+9), 0x1.ffffffffffd3ap-1023); // The first value for which the result flushes to subnormal
try expectEqual(exp2(0x1.fffffffffffffp+1023), math.inf(f64)); // Max input value
try expectEqual(exp2(0x1p-1074), 1); // Min positive input value
try expectEqual(exp2(-0x1p-1074), 1); // Min negative input value
try expectEqual(exp2(0x1p-1022), 1); // First positive subnormal input
try expectEqual(exp2(-0x1p-1022), 1); // First negative subnormal input
}

View file

@ -7,7 +7,8 @@
const std = @import("std");
const builtin = @import("builtin");
const math = std.math;
const testing = std.testing;
const expect = std.testing.expect;
const expectEqual = std.testing.expectEqual;
const arch = builtin.cpu.arch;
const common = @import("common.zig");
@ -110,8 +111,8 @@ pub fn log(x_: f64) callconv(.c) f64 {
// subnormal, scale x
k -= 54;
x *= 0x1.0p54;
hx = @intCast(@as(u64, @bitCast(ix)) >> 32);
x *= 0x1p54;
hx = @intCast(@as(u64, @bitCast(x)) >> 32);
} else if (hx >= 0x7FF00000) {
return x;
} else if (hx == 0x3FF00000 and ix << 32 == 0) {
@ -159,38 +160,72 @@ pub fn logl(x: c_longdouble) callconv(.c) c_longdouble {
}
}
test "ln32" {
const epsilon = 0.000001;
try testing.expect(math.approxEqAbs(f32, logf(0.2), -1.609438, epsilon));
try testing.expect(math.approxEqAbs(f32, logf(0.8923), -0.113953, epsilon));
try testing.expect(math.approxEqAbs(f32, logf(1.5), 0.405465, epsilon));
try testing.expect(math.approxEqAbs(f32, logf(37.45), 3.623007, epsilon));
try testing.expect(math.approxEqAbs(f32, logf(89.123), 4.490017, epsilon));
try testing.expect(math.approxEqAbs(f32, logf(123123.234375), 11.720941, epsilon));
test "logf() special" {
try expectEqual(logf(0.0), -math.inf(f32));
try expectEqual(logf(-0.0), -math.inf(f32));
try expect(math.isPositiveZero(logf(1.0)));
try expectEqual(logf(math.e), 1.0);
try expectEqual(logf(math.inf(f32)), math.inf(f32));
try expect(math.isNan(logf(-1.0)));
try expect(math.isNan(logf(-math.inf(f32))));
try expect(math.isNan(logf(math.nan(f32))));
try expect(math.isNan(logf(math.snan(f32))));
}
test "ln64" {
const epsilon = 0.000001;
try testing.expect(math.approxEqAbs(f64, log(0.2), -1.609438, epsilon));
try testing.expect(math.approxEqAbs(f64, log(0.8923), -0.113953, epsilon));
try testing.expect(math.approxEqAbs(f64, log(1.5), 0.405465, epsilon));
try testing.expect(math.approxEqAbs(f64, log(37.45), 3.623007, epsilon));
try testing.expect(math.approxEqAbs(f64, log(89.123), 4.490017, epsilon));
try testing.expect(math.approxEqAbs(f64, log(123123.234375), 11.720941, epsilon));
test "logf() sanity" {
try expect(math.isNan(logf(-0x1.0223a0p+3)));
try expectEqual(logf(0x1.161868p+2), 0x1.7815b0p+0);
try expect(math.isNan(logf(-0x1.0c34b4p+3)));
try expect(math.isNan(logf(-0x1.a206f0p+2)));
try expectEqual(logf(0x1.288bbcp+3), 0x1.1cfcd6p+1);
try expectEqual(logf(0x1.52efd0p-1), -0x1.a6694cp-2);
try expect(math.isNan(logf(-0x1.a05cc8p-2)));
try expectEqual(logf(0x1.1f9efap-1), -0x1.2742bap-1);
try expectEqual(logf(0x1.8c5db0p-1), -0x1.062160p-2);
try expect(math.isNan(logf(-0x1.5b86eap-1)));
}
test "ln32.special" {
try testing.expect(math.isPositiveInf(logf(math.inf(f32))));
try testing.expect(math.isNegativeInf(logf(0.0)));
try testing.expect(math.isNan(logf(-1.0)));
try testing.expect(math.isNan(logf(math.nan(f32))));
test "logf() boundary" {
try expectEqual(logf(0x1.fffffep+127), 0x1.62e430p+6); // Max input value
try expectEqual(logf(0x1p-149), -0x1.9d1da0p+6); // Min positive input value
try expect(math.isNan(logf(-0x1p-149))); // Min negative input value
try expectEqual(logf(0x1.000002p+0), 0x1.fffffep-24); // Last value before result reaches +0
try expectEqual(logf(0x1.fffffep-1), -0x1p-24); // Last value before result reaches -0
try expectEqual(logf(0x1p-126), -0x1.5d58a0p+6); // First subnormal
try expect(math.isNan(logf(-0x1p-126))); // First negative subnormal
}
test "ln64.special" {
try testing.expect(math.isPositiveInf(log(math.inf(f64))));
try testing.expect(math.isNegativeInf(log(0.0)));
try testing.expect(math.isNan(log(-1.0)));
try testing.expect(math.isNan(log(math.nan(f64))));
test "log() special" {
try expectEqual(log(0.0), -math.inf(f64));
try expectEqual(log(-0.0), -math.inf(f64));
try expect(math.isPositiveZero(log(1.0)));
try expectEqual(log(math.e), 1.0);
try expectEqual(log(math.inf(f64)), math.inf(f64));
try expect(math.isNan(log(-1.0)));
try expect(math.isNan(log(-math.inf(f64))));
try expect(math.isNan(log(math.nan(f64))));
try expect(math.isNan(log(math.snan(f64))));
}
test "log() sanity" {
try expect(math.isNan(log(-0x1.02239f3c6a8f1p+3)));
try expectEqual(log(0x1.161868e18bc67p+2), 0x1.7815b08f99c65p+0);
try expect(math.isNan(log(-0x1.0c34b3e01e6e7p+3)));
try expect(math.isNan(log(-0x1.a206f0a19dcc4p+2)));
try expectEqual(log(0x1.288bbb0d6a1e6p+3), 0x1.1cfcd53d72604p+1);
try expectEqual(log(0x1.52efd0cd80497p-1), -0x1.a6694a4a85621p-2);
try expect(math.isNan(log(-0x1.a05cc754481d1p-2)));
try expectEqual(log(0x1.1f9ef934745cbp-1), -0x1.2742bc03d02ddp-1);
try expectEqual(log(0x1.8c5db097f7442p-1), -0x1.06215de4a3f92p-2);
try expect(math.isNan(log(-0x1.5b86ea8118a0ep-1)));
}
test "log() boundary" {
try expectEqual(log(0x1.fffffffffffffp+1023), 0x1.62e42fefa39efp+9); // Max input value
try expectEqual(log(0x1p-1074), -0x1.74385446d71c3p+9); // Min positive input value
try expect(math.isNan(log(-0x1p-1074))); // Min negative input value
try expectEqual(log(0x1.0000000000001p+0), 0x1.fffffffffffffp-53); // Last value before result reaches +0
try expectEqual(log(0x1.fffffffffffffp-1), -0x1p-53); // Last value before result reaches -0
try expectEqual(log(0x1p-1022), -0x1.6232bdd7abcd2p+9); // First subnormal
try expect(math.isNan(log(-0x1p-1022))); // First negative subnormal
}

View file

@ -7,7 +7,8 @@
const std = @import("std");
const builtin = @import("builtin");
const math = std.math;
const testing = std.testing;
const expect = std.testing.expect;
const expectEqual = std.testing.expectEqual;
const maxInt = std.math.maxInt;
const arch = builtin.cpu.arch;
const common = @import("common.zig");
@ -187,38 +188,74 @@ pub fn log10l(x: c_longdouble) callconv(.c) c_longdouble {
}
}
test "log10_32" {
const epsilon = 0.000001;
try testing.expect(math.approxEqAbs(f32, log10f(0.2), -0.698970, epsilon));
try testing.expect(math.approxEqAbs(f32, log10f(0.8923), -0.049489, epsilon));
try testing.expect(math.approxEqAbs(f32, log10f(1.5), 0.176091, epsilon));
try testing.expect(math.approxEqAbs(f32, log10f(37.45), 1.573452, epsilon));
try testing.expect(math.approxEqAbs(f32, log10f(89.123), 1.94999, epsilon));
try testing.expect(math.approxEqAbs(f32, log10f(123123.234375), 5.09034, epsilon));
test "log10f() special" {
try expectEqual(log10f(0.0), -math.inf(f32));
try expectEqual(log10f(-0.0), -math.inf(f32));
try expect(math.isPositiveZero(log10f(1.0)));
try expectEqual(log10f(10.0), 1.0);
try expectEqual(log10f(0.1), -1.0);
try expectEqual(log10f(math.inf(f32)), math.inf(f32));
try expect(math.isNan(log10f(-1.0)));
try expect(math.isNan(log10f(-math.inf(f32))));
try expect(math.isNan(log10f(math.nan(f32))));
try expect(math.isNan(log10f(math.snan(f32))));
}
test "log10_64" {
const epsilon = 0.000001;
try testing.expect(math.approxEqAbs(f64, log10(0.2), -0.698970, epsilon));
try testing.expect(math.approxEqAbs(f64, log10(0.8923), -0.049489, epsilon));
try testing.expect(math.approxEqAbs(f64, log10(1.5), 0.176091, epsilon));
try testing.expect(math.approxEqAbs(f64, log10(37.45), 1.573452, epsilon));
try testing.expect(math.approxEqAbs(f64, log10(89.123), 1.94999, epsilon));
try testing.expect(math.approxEqAbs(f64, log10(123123.234375), 5.09034, epsilon));
test "log10f() sanity" {
try expect(math.isNan(log10f(-0x1.0223a0p+3)));
try expectEqual(log10f(0x1.161868p+2), 0x1.46a9bcp-1);
try expect(math.isNan(log10f(-0x1.0c34b4p+3)));
try expect(math.isNan(log10f(-0x1.a206f0p+2)));
try expectEqual(log10f(0x1.288bbcp+3), 0x1.ef1300p-1);
try expectEqual(log10f(0x1.52efd0p-1), -0x1.6ee6dcp-3); // Disagrees with GCC in last bit
try expect(math.isNan(log10f(-0x1.a05cc8p-2)));
try expectEqual(log10f(0x1.1f9efap-1), -0x1.0075ccp-2);
try expectEqual(log10f(0x1.8c5db0p-1), -0x1.c75df8p-4);
try expect(math.isNan(log10f(-0x1.5b86eap-1)));
}
test "log10_32.special" {
try testing.expect(math.isPositiveInf(log10f(math.inf(f32))));
try testing.expect(math.isNegativeInf(log10f(0.0)));
try testing.expect(math.isNan(log10f(-1.0)));
try testing.expect(math.isNan(log10f(math.nan(f32))));
test "log10f() boundary" {
try expectEqual(log10f(0x1.fffffep+127), 0x1.344136p+5); // Max input value
try expectEqual(log10f(0x1p-149), -0x1.66d3e8p+5); // Min positive input value
try expect(math.isNan(log10f(-0x1p-149))); // Min negative input value
try expectEqual(log10f(0x1.000002p+0), 0x1.bcb7b0p-25); // Last value before result reaches +0
try expectEqual(log10f(0x1.fffffep-1), -0x1.bcb7b2p-26); // Last value before result reaches -0
try expectEqual(log10f(0x1p-126), -0x1.2f7030p+5); // First subnormal
try expect(math.isNan(log10f(-0x1p-126))); // First negative subnormal
}
test "log10_64.special" {
try testing.expect(math.isPositiveInf(log10(math.inf(f64))));
try testing.expect(math.isNegativeInf(log10(0.0)));
try testing.expect(math.isNan(log10(-1.0)));
try testing.expect(math.isNan(log10(math.nan(f64))));
test "log10() special" {
try expectEqual(log10(0.0), -math.inf(f64));
try expectEqual(log10(-0.0), -math.inf(f64));
try expect(math.isPositiveZero(log10(1.0)));
try expectEqual(log10(10.0), 1.0);
try expectEqual(log10(0.1), -1.0);
try expectEqual(log10(math.inf(f64)), math.inf(f64));
try expect(math.isNan(log10(-1.0)));
try expect(math.isNan(log10(-math.inf(f64))));
try expect(math.isNan(log10(math.nan(f64))));
try expect(math.isNan(log10(math.snan(f64))));
}
test "log10() sanity" {
try expect(math.isNan(log10(-0x1.02239f3c6a8f1p+3)));
try expectEqual(log10(0x1.161868e18bc67p+2), 0x1.46a9bd1d2eb87p-1);
try expect(math.isNan(log10(-0x1.0c34b3e01e6e7p+3)));
try expect(math.isNan(log10(-0x1.a206f0a19dcc4p+2)));
try expectEqual(log10(0x1.288bbb0d6a1e6p+3), 0x1.ef12fff994862p-1);
try expectEqual(log10(0x1.52efd0cd80497p-1), -0x1.6ee6db5a155cbp-3);
try expect(math.isNan(log10(-0x1.a05cc754481d1p-2)));
try expectEqual(log10(0x1.1f9ef934745cbp-1), -0x1.0075cda79d321p-2);
try expectEqual(log10(0x1.8c5db097f7442p-1), -0x1.c75df6442465ap-4);
try expect(math.isNan(log10(-0x1.5b86ea8118a0ep-1)));
}
test "log10() boundary" {
try expectEqual(log10(0x1.fffffffffffffp+1023), 0x1.34413509f79ffp+8); // Max input value
try expectEqual(log10(0x1p-1074), -0x1.434e6420f4374p+8); // Min positive input value
try expect(math.isNan(log10(-0x1p-1074))); // Min negative input value
try expectEqual(log10(0x1.0000000000001p+0), 0x1.bcb7b1526e50dp-54); // Last value before result reaches +0
try expectEqual(log10(0x1.fffffffffffffp-1), -0x1.bcb7b1526e50fp-55); // Last value before result reaches -0
try expectEqual(log10(0x1p-1022), -0x1.33a7146f72a42p+8); // First subnormal
try expect(math.isNan(log10(-0x1p-1022))); // First negative subnormal
}

View file

@ -8,6 +8,7 @@ const std = @import("std");
const builtin = @import("builtin");
const math = std.math;
const expect = std.testing.expect;
const expectEqual = std.testing.expectEqual;
const maxInt = std.math.maxInt;
const arch = builtin.cpu.arch;
const common = @import("common.zig");
@ -179,36 +180,73 @@ pub fn log2l(x: c_longdouble) callconv(.c) c_longdouble {
}
}
test "log2_32" {
const epsilon = 0.000001;
try expect(math.approxEqAbs(f32, log2f(0.2), -2.321928, epsilon));
try expect(math.approxEqAbs(f32, log2f(0.8923), -0.164399, epsilon));
try expect(math.approxEqAbs(f32, log2f(1.5), 0.584962, epsilon));
try expect(math.approxEqAbs(f32, log2f(37.45), 5.226894, epsilon));
try expect(math.approxEqAbs(f32, log2f(123123.234375), 16.909744, epsilon));
}
test "log2_64" {
const epsilon = 0.000001;
try expect(math.approxEqAbs(f64, log2(0.2), -2.321928, epsilon));
try expect(math.approxEqAbs(f64, log2(0.8923), -0.164399, epsilon));
try expect(math.approxEqAbs(f64, log2(1.5), 0.584962, epsilon));
try expect(math.approxEqAbs(f64, log2(37.45), 5.226894, epsilon));
try expect(math.approxEqAbs(f64, log2(123123.234375), 16.909744, epsilon));
}
test "log2_32.special" {
try expect(math.isPositiveInf(log2f(math.inf(f32))));
try expect(math.isNegativeInf(log2f(0.0)));
test "log2f() special" {
try expectEqual(log2f(0.0), -math.inf(f32));
try expectEqual(log2f(-0.0), -math.inf(f32));
try expect(math.isPositiveZero(log2f(1.0)));
try expectEqual(log2f(2.0), 1.0);
try expectEqual(log2f(math.inf(f32)), math.inf(f32));
try expect(math.isNan(log2f(-1.0)));
try expect(math.isNan(log2f(-math.inf(f32))));
try expect(math.isNan(log2f(math.nan(f32))));
try expect(math.isNan(log2f(math.snan(f32))));
}
test "log2_64.special" {
try expect(math.isPositiveInf(log2(math.inf(f64))));
try expect(math.isNegativeInf(log2(0.0)));
try expect(math.isNan(log2(-1.0)));
try expect(math.isNan(log2(math.nan(f64))));
test "log2f() sanity" {
try expect(math.isNan(log2f(-0x1.0223a0p+3)));
try expectEqual(log2f(0x1.161868p+2), 0x1.0f49acp+1);
try expect(math.isNan(log2f(-0x1.0c34b4p+3)));
try expect(math.isNan(log2f(-0x1.a206f0p+2)));
try expectEqual(log2f(0x1.288bbcp+3), 0x1.9b2676p+1);
try expectEqual(log2f(0x1.52efd0p-1), -0x1.30b494p-1); // Disagrees with GCC in last bit
try expect(math.isNan(log2f(-0x1.a05cc8p-2)));
try expectEqual(log2f(0x1.1f9efap-1), -0x1.a9f89ap-1);
try expectEqual(log2f(0x1.8c5db0p-1), -0x1.7a2c96p-2);
try expect(math.isNan(log2f(-0x1.5b86eap-1)));
}
test "log2f() boundary" {
try expectEqual(log2f(0x1.fffffep+127), 0x1p+7); // Max input value
try expectEqual(log2f(0x1p-149), -0x1.2ap+7); // Min positive input value
try expect(math.isNan(log2f(-0x1p-149))); // Min negative input value
try expectEqual(log2f(0x1.000002p+0), 0x1.715474p-23); // Last value before result reaches +0
try expectEqual(log2f(0x1.fffffep-1), -0x1.715478p-24); // Last value before result reaches -0
try expectEqual(log2f(0x1p-126), -0x1.f8p+6); // First subnormal
try expect(math.isNan(log2f(-0x1p-126))); // First negative subnormal
}
test "log2() special" {
try expectEqual(log2(0.0), -math.inf(f64));
try expectEqual(log2(-0.0), -math.inf(f64));
try expect(math.isPositiveZero(log2(1.0)));
try expectEqual(log2(2.0), 1.0);
try expectEqual(log2(math.inf(f64)), math.inf(f64));
try expect(math.isNan(log2(-1.0)));
try expect(math.isNan(log2(-math.inf(f64))));
try expect(math.isNan(log2(math.nan(f64))));
try expect(math.isNan(log2(math.snan(f64))));
}
test "log2() sanity" {
try expect(math.isNan(log2(-0x1.02239f3c6a8f1p+3)));
try expectEqual(log2(0x1.161868e18bc67p+2), 0x1.0f49ac3838580p+1);
try expect(math.isNan(log2(-0x1.0c34b3e01e6e7p+3)));
try expect(math.isNan(log2(-0x1.a206f0a19dcc4p+2)));
try expectEqual(log2(0x1.288bbb0d6a1e6p+3), 0x1.9b26760c2a57ep+1);
try expectEqual(log2(0x1.52efd0cd80497p-1), -0x1.30b490ef684c7p-1);
try expect(math.isNan(log2(-0x1.a05cc754481d1p-2)));
try expectEqual(log2(0x1.1f9ef934745cbp-1), -0x1.a9f89b5f5acb8p-1);
try expectEqual(log2(0x1.8c5db097f7442p-1), -0x1.7a2c947173f06p-2);
try expect(math.isNan(log2(-0x1.5b86ea8118a0ep-1)));
}
test "log2() boundary" {
try expectEqual(log2(0x1.fffffffffffffp+1023), 0x1p+10); // Max input value
try expectEqual(log2(0x1p-1074), -0x1.0c8p+10); // Min positive input value
try expect(math.isNan(log2(-0x1p-1074))); // Min negative input value
try expectEqual(log2(0x1.0000000000001p+0), 0x1.71547652b82fdp-52); // Last value before result reaches +0
try expectEqual(log2(0x1.fffffffffffffp-1), -0x1.71547652b82fep-53); // Last value before result reaches -0
try expectEqual(log2(0x1p-1022), -0x1.ffp+9); // First subnormal
try expect(math.isNan(log2(-0x1p-1022))); // First negative subnormal
}

View file

@ -10,6 +10,7 @@ const std = @import("../std.zig");
const math = std.math;
const mem = std.mem;
const expect = std.testing.expect;
const expectEqual = std.testing.expectEqual;
/// Returns e raised to the power of x, minus 1 (e^x - 1). This is more accurate than exp(e, x) - 1
/// when x is near 0.
@ -39,9 +40,9 @@ fn expm1_32(x_: f32) f32 {
const Q2: f32 = 1.5807170421e-3;
var x = x_;
const ux = @as(u32, @bitCast(x));
const ux: u32 = @bitCast(x);
const hx = ux & 0x7FFFFFFF;
const sign = hx >> 31;
const sign = ux >> 31;
// TODO: Shouldn't need this check explicitly.
if (math.isNegativeInf(x)) {
@ -147,7 +148,7 @@ fn expm1_32(x_: f32) f32 {
return y - 1.0;
}
const uf = @as(f32, @bitCast(@as(u32, @intCast(0x7F -% k)) << 23));
const uf: f32 = @bitCast(@as(u32, @intCast(0x7F -% k)) << 23);
if (k < 23) {
return (x - e + (1 - uf)) * twopk;
} else {
@ -286,39 +287,77 @@ fn expm1_64(x_: f64) f64 {
}
}
test expm1 {
try expect(expm1(@as(f32, 0.0)) == expm1_32(0.0));
try expect(expm1(@as(f64, 0.0)) == expm1_64(0.0));
}
test expm1_32 {
const epsilon = 0.000001;
test "expm1_32() special" {
try expect(math.isPositiveZero(expm1_32(0.0)));
try expect(math.approxEqAbs(f32, expm1_32(0.0), 0.0, epsilon));
try expect(math.approxEqAbs(f32, expm1_32(0.2), 0.221403, epsilon));
try expect(math.approxEqAbs(f32, expm1_32(0.8923), 1.440737, epsilon));
try expect(math.approxEqAbs(f32, expm1_32(1.5), 3.481689, epsilon));
}
test expm1_64 {
const epsilon = 0.000001;
try expect(math.isPositiveZero(expm1_64(0.0)));
try expect(math.approxEqAbs(f64, expm1_64(0.0), 0.0, epsilon));
try expect(math.approxEqAbs(f64, expm1_64(0.2), 0.221403, epsilon));
try expect(math.approxEqAbs(f64, expm1_64(0.8923), 1.440737, epsilon));
try expect(math.approxEqAbs(f64, expm1_64(1.5), 3.481689, epsilon));
}
test "expm1_32.special" {
try expect(math.isPositiveInf(expm1_32(math.inf(f32))));
try expect(expm1_32(-math.inf(f32)) == -1.0);
try expect(math.isNegativeZero(expm1_32(-0.0)));
try expectEqual(expm1_32(math.ln2), 1.0);
try expectEqual(expm1_32(math.inf(f32)), math.inf(f32));
try expectEqual(expm1_32(-math.inf(f32)), -1.0);
try expect(math.isNan(expm1_32(math.nan(f32))));
try expect(math.isNan(expm1_32(math.snan(f32))));
}
test "expm1_64.special" {
try expect(math.isPositiveInf(expm1_64(math.inf(f64))));
try expect(expm1_64(-math.inf(f64)) == -1.0);
try expect(math.isNan(expm1_64(math.nan(f64))));
test "expm1_32() sanity" {
try expectEqual(expm1_32(-0x1.0223a0p+3), -0x1.ffd6e0p-1);
try expectEqual(expm1_32(0x1.161868p+2), 0x1.30712ap+6);
try expectEqual(expm1_32(-0x1.0c34b4p+3), -0x1.ffe1fap-1);
try expectEqual(expm1_32(-0x1.a206f0p+2), -0x1.ff4116p-1);
try expectEqual(expm1_32(0x1.288bbcp+3), 0x1.4ab480p+13); // Disagrees with GCC in last bit
try expectEqual(expm1_32(0x1.52efd0p-1), 0x1.e09536p-1);
try expectEqual(expm1_32(-0x1.a05cc8p-2), -0x1.561c3ep-2);
try expectEqual(expm1_32(0x1.1f9efap-1), 0x1.81ec4ep-1);
try expectEqual(expm1_32(0x1.8c5db0p-1), 0x1.2b3364p+0);
try expectEqual(expm1_32(-0x1.5b86eap-1), -0x1.f8951ap-2);
}
test "expm1_32() boundary" {
// TODO: The last value before inf is actually 0x1.62e300p+6 -> 0x1.ff681ep+127
// try expectEqual(expm1_32(0x1.62e42ep+6), 0x1.ffff08p+127); // Last value before result is inf
try expectEqual(expm1_32(0x1.62e430p+6), math.inf(f32)); // First value that gives inf
try expectEqual(expm1_32(0x1.fffffep+127), math.inf(f32)); // Max input value
try expectEqual(expm1_32(0x1p-149), 0x1p-149); // Min positive input value
try expectEqual(expm1_32(-0x1p-149), -0x1p-149); // Min negative input value
try expectEqual(expm1_32(0x1p-126), 0x1p-126); // First positive subnormal input
try expectEqual(expm1_32(-0x1p-126), -0x1p-126); // First negative subnormal input
try expectEqual(expm1_32(0x1.fffffep-125), 0x1.fffffep-125); // Last positive value before subnormal
try expectEqual(expm1_32(-0x1.fffffep-125), -0x1.fffffep-125); // Last negative value before subnormal
try expectEqual(expm1_32(-0x1.154244p+4), -0x1.fffffep-1); // Last value before result is -1
try expectEqual(expm1_32(-0x1.154246p+4), -1); // First value where result is -1
}
test "expm1_64() special" {
try expect(math.isPositiveZero(expm1_64(0.0)));
try expect(math.isNegativeZero(expm1_64(-0.0)));
try expectEqual(expm1_64(math.ln2), 1.0);
try expectEqual(expm1_64(math.inf(f64)), math.inf(f64));
try expectEqual(expm1_64(-math.inf(f64)), -1.0);
try expect(math.isNan(expm1_64(math.nan(f64))));
try expect(math.isNan(expm1_64(math.snan(f64))));
}
test "expm1_64() sanity" {
try expectEqual(expm1_64(-0x1.02239f3c6a8f1p+3), -0x1.ffd6df9b02b3ep-1);
try expectEqual(expm1_64(0x1.161868e18bc67p+2), 0x1.30712ed238c04p+6);
try expectEqual(expm1_64(-0x1.0c34b3e01e6e7p+3), -0x1.ffe1f94e493e7p-1);
try expectEqual(expm1_64(-0x1.a206f0a19dcc4p+2), -0x1.ff4115c03f78dp-1);
try expectEqual(expm1_64(0x1.288bbb0d6a1e6p+3), 0x1.4ab477496e07ep+13);
try expectEqual(expm1_64(0x1.52efd0cd80497p-1), 0x1.e095382100a01p-1);
try expectEqual(expm1_64(-0x1.a05cc754481d1p-2), -0x1.561c3e0582be6p-2);
try expectEqual(expm1_64(0x1.1f9ef934745cbp-1), 0x1.81ec4cd4d4a8fp-1);
try expectEqual(expm1_64(0x1.8c5db097f7442p-1), 0x1.2b3363a944bf7p+0);
try expectEqual(expm1_64(-0x1.5b86ea8118a0ep-1), -0x1.f8951aebffbafp-2);
}
test "expm1_64() boundary" {
try expectEqual(expm1_64(0x1.62e42fefa39efp+9), 0x1.fffffffffff2ap+1023); // Last value before result is inf
try expectEqual(expm1_64(0x1.62e42fefa39f0p+9), math.inf(f64)); // First value that gives inf
try expectEqual(expm1_64(0x1.fffffffffffffp+1023), math.inf(f64)); // Max input value
try expectEqual(expm1_64(0x1p-1074), 0x1p-1074); // Min positive input value
try expectEqual(expm1_64(-0x1p-1074), -0x1p-1074); // Min negative input value
try expectEqual(expm1_64(0x1p-1022), 0x1p-1022); // First positive subnormal input
try expectEqual(expm1_64(-0x1p-1022), -0x1p-1022); // First negative subnormal input
try expectEqual(expm1_64(0x1.fffffffffffffp-1021), 0x1.fffffffffffffp-1021); // Last positive value before subnormal
try expectEqual(expm1_64(-0x1.fffffffffffffp-1021), -0x1.fffffffffffffp-1021); // Last negative value before subnormal
try expectEqual(expm1_64(-0x1.2b708872320e1p+5), -0x1.fffffffffffffp-1); // Last value before result is -1
try expectEqual(expm1_64(-0x1.2b708872320e2p+5), -1); // First value where result is -1
}

View file

@ -8,6 +8,7 @@ const std = @import("../std.zig");
const math = std.math;
const mem = std.mem;
const expect = std.testing.expect;
const expectEqual = std.testing.expectEqual;
/// Returns the natural logarithm of 1 + x with greater accuracy when x is near zero.
///
@ -182,49 +183,72 @@ fn log1p_64(x: f64) f64 {
return s * (hfsq + R) + (dk * ln2_lo + c) - hfsq + f + dk * ln2_hi;
}
test log1p {
try expect(log1p(@as(f32, 0.0)) == log1p_32(0.0));
try expect(log1p(@as(f64, 0.0)) == log1p_64(0.0));
}
test log1p_32 {
const epsilon = 0.000001;
try expect(math.approxEqAbs(f32, log1p_32(0.0), 0.0, epsilon));
try expect(math.approxEqAbs(f32, log1p_32(0.2), 0.182322, epsilon));
try expect(math.approxEqAbs(f32, log1p_32(0.8923), 0.637793, epsilon));
try expect(math.approxEqAbs(f32, log1p_32(1.5), 0.916291, epsilon));
try expect(math.approxEqAbs(f32, log1p_32(37.45), 3.649359, epsilon));
try expect(math.approxEqAbs(f32, log1p_32(89.123), 4.501175, epsilon));
try expect(math.approxEqAbs(f32, log1p_32(123123.234375), 11.720949, epsilon));
}
test log1p_64 {
const epsilon = 0.000001;
try expect(math.approxEqAbs(f64, log1p_64(0.0), 0.0, epsilon));
try expect(math.approxEqAbs(f64, log1p_64(0.2), 0.182322, epsilon));
try expect(math.approxEqAbs(f64, log1p_64(0.8923), 0.637793, epsilon));
try expect(math.approxEqAbs(f64, log1p_64(1.5), 0.916291, epsilon));
try expect(math.approxEqAbs(f64, log1p_64(37.45), 3.649359, epsilon));
try expect(math.approxEqAbs(f64, log1p_64(89.123), 4.501175, epsilon));
try expect(math.approxEqAbs(f64, log1p_64(123123.234375), 11.720949, epsilon));
}
test "log1p_32.special" {
try expect(math.isPositiveInf(log1p_32(math.inf(f32))));
test "log1p_32() special" {
try expect(math.isPositiveZero(log1p_32(0.0)));
try expect(math.isNegativeZero(log1p_32(-0.0)));
try expect(math.isNegativeInf(log1p_32(-1.0)));
try expectEqual(log1p_32(-1.0), -math.inf(f32));
try expectEqual(log1p_32(1.0), math.ln2);
try expectEqual(log1p_32(math.inf(f32)), math.inf(f32));
try expect(math.isNan(log1p_32(-2.0)));
try expect(math.isNan(log1p_32(-math.inf(f32))));
try expect(math.isNan(log1p_32(math.nan(f32))));
try expect(math.isNan(log1p_32(math.snan(f32))));
}
test "log1p_64.special" {
try expect(math.isPositiveInf(log1p_64(math.inf(f64))));
test "log1p_32() sanity" {
try expect(math.isNan(log1p_32(-0x1.0223a0p+3)));
try expectEqual(log1p_32(0x1.161868p+2), 0x1.ad1bdcp+0);
try expect(math.isNan(log1p_32(-0x1.0c34b4p+3)));
try expect(math.isNan(log1p_32(-0x1.a206f0p+2)));
try expectEqual(log1p_32(0x1.288bbcp+3), 0x1.2a1ab8p+1);
try expectEqual(log1p_32(0x1.52efd0p-1), 0x1.041a4ep-1);
try expectEqual(log1p_32(-0x1.a05cc8p-2), -0x1.0b3596p-1);
try expectEqual(log1p_32(0x1.1f9efap-1), 0x1.c88344p-2);
try expectEqual(log1p_32(0x1.8c5db0p-1), 0x1.258a8ep-1);
try expectEqual(log1p_32(-0x1.5b86eap-1), -0x1.22b542p+0);
}
test "log1p_32() boundary" {
try expectEqual(log1p_32(0x1.fffffep+127), 0x1.62e430p+6); // Max input value
try expectEqual(log1p_32(0x1p-149), 0x1p-149); // Min positive input value
try expectEqual(log1p_32(-0x1p-149), -0x1p-149); // Min negative input value
try expectEqual(log1p_32(0x1p-126), 0x1p-126); // First subnormal
try expectEqual(log1p_32(-0x1p-126), -0x1p-126); // First negative subnormal
try expectEqual(log1p_32(-0x1.fffffep-1), -0x1.0a2b24p+4); // Last value before result is -inf
try expect(math.isNan(log1p_32(-0x1.000002p+0))); // First value where result is nan
}
test "log1p_64() special" {
try expect(math.isPositiveZero(log1p_64(0.0)));
try expect(math.isNegativeZero(log1p_64(-0.0)));
try expect(math.isNegativeInf(log1p_64(-1.0)));
try expectEqual(log1p_64(-1.0), -math.inf(f64));
try expectEqual(log1p_64(1.0), math.ln2);
try expectEqual(log1p_64(math.inf(f64)), math.inf(f64));
try expect(math.isNan(log1p_64(-2.0)));
try expect(math.isNan(log1p_64(-math.inf(f64))));
try expect(math.isNan(log1p_64(math.nan(f64))));
try expect(math.isNan(log1p_64(math.snan(f64))));
}
test "log1p_64() sanity" {
try expect(math.isNan(log1p_64(-0x1.02239f3c6a8f1p+3)));
try expectEqual(log1p_64(0x1.161868e18bc67p+2), 0x1.ad1bdd1e9e686p+0); // Disagrees with GCC in last bit
try expect(math.isNan(log1p_64(-0x1.0c34b3e01e6e7p+3)));
try expect(math.isNan(log1p_64(-0x1.a206f0a19dcc4p+2)));
try expectEqual(log1p_64(0x1.288bbb0d6a1e6p+3), 0x1.2a1ab8365b56fp+1);
try expectEqual(log1p_64(0x1.52efd0cd80497p-1), 0x1.041a4ec2a680ap-1);
try expectEqual(log1p_64(-0x1.a05cc754481d1p-2), -0x1.0b3595423aec1p-1);
try expectEqual(log1p_64(0x1.1f9ef934745cbp-1), 0x1.c8834348a846ep-2);
try expectEqual(log1p_64(0x1.8c5db097f7442p-1), 0x1.258a8e8a35bbfp-1);
try expectEqual(log1p_64(-0x1.5b86ea8118a0ep-1), -0x1.22b5426327502p+0);
}
test "log1p_64() boundary" {
try expectEqual(log1p_64(0x1.fffffffffffffp+1023), 0x1.62e42fefa39efp+9); // Max input value
try expectEqual(log1p_64(0x1p-1074), 0x1p-1074); // Min positive input value
try expectEqual(log1p_64(-0x1p-1074), -0x1p-1074); // Min negative input value
try expectEqual(log1p_64(0x1p-1022), 0x1p-1022); // First subnormal
try expectEqual(log1p_64(-0x1p-1022), -0x1p-1022); // First negative subnormal
try expectEqual(log1p_64(-0x1.fffffffffffffp-1), -0x1.25e4f7b2737fap+5); // Last value before result is -inf
try expect(math.isNan(log1p_64(-0x1.0000000000001p+0))); // First value where result is nan
}