hare

[hare] The Hare programming language
git clone https://git.torresjrjr.com/hare.git
Log | Files | Refs | README | LICENSE

commit 0e4d23b852c210e65ed9f2b85312bad6208d021b
parent 696e57b2dbf9376d4be889cef45731fec9745012
Author: Bor Grošelj Simić <bgs@turminal.net>
Date:   Sun, 19 Feb 2023 05:29:01 +0100

move tests depending on +test into +test

This used to work because harec didn't typecheck @test functions when
called without -T

Signed-off-by: Bor Grošelj Simić <bgs@turminal.net>

Diffstat:
Mcrypto/bigint/+test/utils.ha | 25+++++++++++++++++++++++++
Mcrypto/bigint/util.ha | 25-------------------------
Mhare/unit/+test.ha | 119+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mhare/unit/process.ha | 119-------------------------------------------------------------------------------
Rmath/data+test.ha -> math/+test/data.ha | 0
Amath/+test/floats.ha | 296+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Amath/+test/math.ha | 287+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Amath/+test/trig.ha | 220+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mmath/floats.ha | 296-------------------------------------------------------------------------------
Mmath/math.ha | 288-------------------------------------------------------------------------------
Mmath/trig.ha | 220-------------------------------------------------------------------------------
Mscripts/gen-stdlib | 6+++++-
Mstdlib.mk | 5++++-
13 files changed, 956 insertions(+), 950 deletions(-)

diff --git a/crypto/bigint/+test/utils.ha b/crypto/bigint/+test/utils.ha @@ -39,3 +39,28 @@ export fn equalshex(x: []word, h: str) bool = { defer free(result); return result == h; }; + +@test fn iszero() void = { + let x = fromhex("210032a0"); + let y = fromhex("00000000"); + + assert(iszero(x) == 0); + assert(iszero(y) == 1); + + free(x); + free(y); +}; + +@test fn zero() void = { + let w: [4]word = [0xffffffff...]; + + // set effective word len to 2 words. + const elen = countbits(w[1..3]); + w[0] = elen; + + zero(w[..3], elen); + + // check if zero does not overwrite more or less than elen + assert(w[0] == elen); + assert(w[3] == 0xffffffff); +}; diff --git a/crypto/bigint/util.ha b/crypto/bigint/util.ha @@ -28,20 +28,6 @@ export fn zero(x: []word, ebitlen: word) void = { bytes::zero((x: *[*]u8)[size(word)..(1 + ewordlen) * size(word)]); }; -@test fn zero() void = { - let w: [4]word = [0xffffffff...]; - - // set effective word len to 2 words. - const elen = countbits(w[1..3]); - w[0] = elen; - - zero(w[..3], elen); - - // check if zero does not overwrite more or less than elen - assert(w[0] == elen); - assert(w[3] == 0xffffffff); -}; - // Checks whether the effective words of 'x' are zero. Returns 1 if so, or 0 // otherwise. fn iszero(x: []word) u32 = { @@ -53,17 +39,6 @@ fn iszero(x: []word) u32 = { return ~(z | -(z: i32): u32) >> 31; }; -@test fn iszero() void = { - let x = fromhex("210032a0"); - let y = fromhex("00000000"); - - assert(iszero(x) == 0); - assert(iszero(y) == 1); - - free(x); - free(y); -}; - fn isodd(x: []word) bool = { return x[1] & 1 == 1; }; diff --git a/hare/unit/+test.ha b/hare/unit/+test.ha @@ -25,3 +25,122 @@ fn freetestctx(ctx: *context) void = { // TODO: Some of this should be in -test types::store_free(ctx.store); }; + +@test fn access() void = { + // TODO: Test error cases, more access types + const ctx = mktestctx(); + defer freetestctx(&ctx); + const object = scope_insert(&ctx, object { + kind = object_kind::BIND, + ident = ["hello"], + name = ["hello"], + _type = &types::builtin_u32, + ... + }); + const aexpr = parse_expr("hello"); + defer ast::expr_finish(aexpr); + const expr = process_access(&ctx, aexpr)!; + const access = expr.expr as access; + const ao = access as access_object; + assert(ao == object); + assert(expr.result == &types::builtin_u32); +}; + +@test fn compound() void = { + const ctx = mktestctx(); + defer freetestctx(&ctx); + const aexpr = parse_expr("{ void; void; void; }"); + defer ast::expr_finish(aexpr); + const expr = process_compound(&ctx, aexpr)!; + assert(expr.result.repr as types::builtin == types::builtin::VOID); + const compound = expr.expr as compound; + assert(len(compound) == 3); + + const aexpr = parse_expr("{ return; }"); + defer ast::expr_finish(aexpr); + const expr = process_compound(&ctx, aexpr)!; + assert(expr.terminates); + + // TODO: test yields +}; + +@test fn constant() void = { + const ctx = mktestctx(); + defer freetestctx(&ctx); + const aexpr = parse_expr("void"); + defer ast::expr_finish(aexpr); + const expr = process_constant(&ctx, aexpr)!; + assert(expr.result.repr as types::builtin == types::builtin::VOID); + const constexpr = expr.expr as constant; + assert(constexpr is void); + + const aexpr = parse_expr("true"); + defer ast::expr_finish(aexpr); + const expr = process_constant(&ctx, aexpr)!; + assert(expr.result.repr as types::builtin == types::builtin::BOOL); + const constexpr = expr.expr as constant; + assert(constexpr as bool == true); + + const aexpr = parse_expr("false"); + defer ast::expr_finish(aexpr); + const expr = process_constant(&ctx, aexpr)!; + assert(expr.result.repr as types::builtin == types::builtin::BOOL); + const constexpr = expr.expr as constant; + assert(constexpr as bool == false); + + const aexpr = parse_expr("null"); + defer ast::expr_finish(aexpr); + const expr = process_constant(&ctx, aexpr)!; + assert(expr.result.repr as types::builtin == types::builtin::NULL); + assert(expr.expr is constant); + + const cases: [_](str, types::builtin, constant) = [ + ("1234", types::builtin::INT, 1234), + ("1234u", types::builtin::UINT, 1234u), + ("\"hello world\"", types::builtin::STR, "hello world"), + ("'!'", types::builtin::RUNE, '!'), + ("13.37", types::builtin::F64, 13.37f64), + ]; + for (let i = 0z; i < len(cases); i += 1) { + const _case = cases[i]; + const aexpr = parse_expr(_case.0); + defer ast::expr_finish(aexpr); + const expr = process_constant(&ctx, aexpr)!; + assert(expr.result.repr as types::builtin == _case.1); + const constexpr = expr.expr as constant; + match (_case.2) { + case let s: str => + assert(constexpr as str == s); + case let r: rune => + assert(constexpr as rune == r); + case let i: i64 => + assert(constexpr as i64 == i); + case let u: u64 => + assert(constexpr as u64 == u); + case let f: f64 => + assert(constexpr as f64 == f); + case void => + abort(); + }; + }; +}; + +@test fn _return() void = { + const ctx = mktestctx(); + defer freetestctx(&ctx); + const aexpr = parse_expr("return;"); + defer ast::expr_finish(aexpr); + const ret_expr = process_return(&ctx, aexpr)!; + assert(ret_expr.terminates); + assert(ret_expr.result.repr as types::builtin == types::builtin::VOID); + const rval = ret_expr.expr as _return; + assert(rval == null); + + const aexpr = parse_expr("return 10;"); + defer ast::expr_finish(aexpr); + const ret_expr = process_return(&ctx, aexpr)!; + assert(ret_expr.terminates); + assert(ret_expr.result.repr as types::builtin == types::builtin::VOID); + const rval = ret_expr.expr as _return; + assert((rval as *expr).expr is constant); +}; diff --git a/hare/unit/process.ha b/hare/unit/process.ha @@ -173,26 +173,6 @@ fn process_access(ctx: *context, aexpr: *ast::expr) (*expr | error) = { }); }; -@test fn access() void = { - // TODO: Test error cases, more access types - const ctx = mktestctx(); - defer freetestctx(&ctx); - const object = scope_insert(&ctx, object { - kind = object_kind::BIND, - ident = ["hello"], - name = ["hello"], - _type = &types::builtin_u32, - ... - }); - const aexpr = parse_expr("hello"); - defer ast::expr_finish(aexpr); - const expr = process_access(&ctx, aexpr)!; - const access = expr.expr as access; - const ao = access as access_object; - assert(ao == object); - assert(expr.result == &types::builtin_u32); -}; - fn process_binding(ctx: *context, aexpr: *ast::expr) (*expr | error) = { const bind = aexpr.expr as ast::binding_expr; assert(!bind.is_static && !bind.is_const); // TODO @@ -250,24 +230,6 @@ fn process_compound(ctx: *context, aexpr: *ast::expr) (*expr | error) = { }); }; -@test fn compound() void = { - const ctx = mktestctx(); - defer freetestctx(&ctx); - const aexpr = parse_expr("{ void; void; void; }"); - defer ast::expr_finish(aexpr); - const expr = process_compound(&ctx, aexpr)!; - assert(expr.result.repr as types::builtin == types::builtin::VOID); - const compound = expr.expr as compound; - assert(len(compound) == 3); - - const aexpr = parse_expr("{ return; }"); - defer ast::expr_finish(aexpr); - const expr = process_compound(&ctx, aexpr)!; - assert(expr.terminates); - - // TODO: test yields -}; - fn process_constant(ctx: *context, aexpr: *ast::expr) (*expr | error) = { const constexpr = aexpr.expr as ast::constant_expr; const (result, ex) = match (constexpr) { @@ -336,67 +298,6 @@ fn process_constant(ctx: *context, aexpr: *ast::expr) (*expr | error) = { }); }; -@test fn constant() void = { - const ctx = mktestctx(); - defer freetestctx(&ctx); - const aexpr = parse_expr("void"); - defer ast::expr_finish(aexpr); - const expr = process_constant(&ctx, aexpr)!; - assert(expr.result.repr as types::builtin == types::builtin::VOID); - const constexpr = expr.expr as constant; - assert(constexpr is void); - - const aexpr = parse_expr("true"); - defer ast::expr_finish(aexpr); - const expr = process_constant(&ctx, aexpr)!; - assert(expr.result.repr as types::builtin == types::builtin::BOOL); - const constexpr = expr.expr as constant; - assert(constexpr as bool == true); - - const aexpr = parse_expr("false"); - defer ast::expr_finish(aexpr); - const expr = process_constant(&ctx, aexpr)!; - assert(expr.result.repr as types::builtin == types::builtin::BOOL); - const constexpr = expr.expr as constant; - assert(constexpr as bool == false); - - const aexpr = parse_expr("null"); - defer ast::expr_finish(aexpr); - const expr = process_constant(&ctx, aexpr)!; - assert(expr.result.repr as types::builtin == types::builtin::NULL); - assert(expr.expr is constant); - - const cases: [_](str, types::builtin, constant) = [ - ("1234", types::builtin::INT, 1234), - ("1234u", types::builtin::UINT, 1234u), - ("\"hello world\"", types::builtin::STR, "hello world"), - ("'!'", types::builtin::RUNE, '!'), - ("13.37", types::builtin::F64, 13.37f64), - ]; - for (let i = 0z; i < len(cases); i += 1) { - const _case = cases[i]; - const aexpr = parse_expr(_case.0); - defer ast::expr_finish(aexpr); - const expr = process_constant(&ctx, aexpr)!; - assert(expr.result.repr as types::builtin == _case.1); - const constexpr = expr.expr as constant; - match (_case.2) { - case let s: str => - assert(constexpr as str == s); - case let r: rune => - assert(constexpr as rune == r); - case let i: i64 => - assert(constexpr as i64 == i); - case let u: u64 => - assert(constexpr as u64 == u); - case let f: f64 => - assert(constexpr as f64 == f); - case void => - abort(); - }; - }; -}; - fn process_return(ctx: *context, aexpr: *ast::expr) (*expr | error) = { const ret = aexpr.expr as ast::return_expr; const rval = match (ret) { @@ -414,23 +315,3 @@ fn process_return(ctx: *context, aexpr: *ast::expr) (*expr | error) = { expr = rval: _return, }); }; - -@test fn _return() void = { - const ctx = mktestctx(); - defer freetestctx(&ctx); - const aexpr = parse_expr("return;"); - defer ast::expr_finish(aexpr); - const ret_expr = process_return(&ctx, aexpr)!; - assert(ret_expr.terminates); - assert(ret_expr.result.repr as types::builtin == types::builtin::VOID); - const rval = ret_expr.expr as _return; - assert(rval == null); - - const aexpr = parse_expr("return 10;"); - defer ast::expr_finish(aexpr); - const ret_expr = process_return(&ctx, aexpr)!; - assert(ret_expr.terminates); - assert(ret_expr.result.repr as types::builtin == types::builtin::VOID); - const rval = ret_expr.expr as _return; - assert((rval as *expr).expr is constant); -}; diff --git a/math/data+test.ha b/math/+test/data.ha diff --git a/math/+test/floats.ha b/math/+test/floats.ha @@ -0,0 +1,296 @@ +@test fn floatbits() void = { + const a: [_]f64 = [INF, -INF, 0.0, 1.0, -1.0, 123456789.0, + F64_MIN, F64_MIN_NORMAL, F64_MAX_NORMAL]; + for (let i = 0z; i < len(a); i += 1) { + assert(f64frombits(f64bits(a[i])) == a[i]); + }; + const a: [_]f32 = [INF, -INF, 0.0, 1.0, -1.0, -123456.0, + F32_MIN, F32_MIN_NORMAL, F32_MAX_NORMAL]; + for (let i = 0z; i < len(a); i += 1) { + assert(f32frombits(f32bits(a[i])) == a[i]); + }; +}; + +@test fn isnan() void = { + assert(isnan(NAN)); + assert(isnan(-NAN)); + assert(isnan(f64frombits(0xfffabcdef1234567))); + assert(!isnan(INF)); + assert(!isnan(1.23f32)); +}; + +@test fn float_normality() void = { + assert(isnormal(0.0)); + assert(isnormal(1.0)); + assert(!isnormal(NAN)); + assert(!isnormal(INF)); + assert(!isnormal(1.0e-310)); + assert(!isnormal(1.0e-40f32)); + + assert(isnormalf32(1.0)); + assert(isnormalf32(0.0)); + assert(!isnormalf32(NAN)); + assert(!isnormalf32(INF)); + assert(!isnormalf32(-1.0e-40)); + assert(isnormalf32(-1.0e-50)); + + assert(isnormalf64(1.0)); + assert(isnormalf64(0.0)); + assert(!isnormalf64(NAN)); + assert(!isnormalf64(INF)); + assert(!isnormalf64(-1.0e-320)); + assert(isnormalf64(-1.0e-330)); + + assert(issubnormal(1.0e-320)); + assert(issubnormal(1.0e-42f32)); + assert(!issubnormal(NAN)); + assert(!issubnormal(INF)); + assert(!issubnormal(1.0)); + assert(!issubnormal(0.0)); + + assert(issubnormalf32(1.0e-45)); + assert(issubnormalf32(-1.0e-39)); + assert(!issubnormalf32(-NAN)); + assert(!issubnormalf32(-INF)); + assert(!issubnormalf32(0.0)); + assert(!issubnormalf32(-1.0e-49)); + + assert(issubnormalf64(5.0e-324)); + assert(issubnormalf64(-2.0e-310)); + assert(!issubnormalf64(-NAN)); + assert(!issubnormalf64(-INF)); + assert(!issubnormalf64(-1.0e-400)); + assert(!issubnormalf64(0.0)); +}; + +@test fn absf() void = { + for (let idx = 0z; idx < len(TEST_INPUTS); idx += 1) { + assert(absf(TEST_INPUTS[idx]) == TEST_ABSF[idx]); + }; + assert(absf64(2f64) == 2f64); + assert(absf32(2.0f32) == 2.0f32); + assert(absf(2f64) == 2f64); + assert(absf(2.0f32) == 2f64); + assert(absf(-2f64) == 2f64); + assert(absf(-2.0f32) == 2.0f32); + assert(absf(0f32) == 0f32); + assert(absf(0f64) == 0f64); +}; + +@test fn copysign() void = { + assert(copysign(100f64, 1f64) == 100f64); + assert(copysign(100f64, -1f64) == -100f64); + assert(copysign(100.0f32, 1.0f32) == 100.0f32); + assert(copysign(100.0f32, -1.0f32) == -100.0f32); + assert(copysign(100f64, 0f64) == 100f64); + assert(copysign(100f64, -0f64) == -100f64); + assert(copysign(0f64, 100f64) == 0f64); + assert(signf(copysign(0f64, 100f64)) > 0); + assert(copysign(0f64, -100f64) == 0f64); + assert(signf(copysign(0f64, -100f64)) < 0); +}; + +@test fn signf() void = { + for (let idx = 0z; idx < len(TEST_INPUTS); idx += 1) { + assert(signf(TEST_INPUTS[idx]) == TEST_SIGNF[idx]); + }; + assert(signf(0f64) == 1i64); + assert(signf(-0f64) == -1i64); + assert(signf(0.0f32) == 1i64); + assert(signf(-0.0f32) == -1i64); + assert(signf(1.5f64) == 1i64); + assert(signf(-1.5f64) == -1i64); + assert(ispositive(1f64)); + assert(!ispositive(-1f64)); + assert(isnegative(-1f64)); + assert(!isnegative(1f64)); +}; + +@test fn normalize() void = { + let res = normalizef64(5.0e-320); + assert(res.0 > F64_MIN_NORMAL); + assert(res.1 < 0i64); + res = normalizef64(5.0e-300); + assert(res.0 == 5.0e-300); + assert(res.1 == 0i64); +}; + +@test fn frexp() void = { + for (let idx = 0z; idx < len(TEST_INPUTS); idx += 1) { + let res = frexp(TEST_INPUTS[idx]); + let expected = TEST_FREXP[idx]; + assert(res.0 == expected.0); + assert(res.1 == expected.1); + }; + let res = frexp(3f64); + assert(res.0 == 0.75f64); + assert(res.1 == 2i64); + res = frexp(2.42f64); + assert(res.0 == 0.605f64); + assert(res.1 == 2i64); + res = frexp(NAN); + assert(res.1 == 0); + res = frexp(INF); + assert(res.1 == 0); +}; + +@test fn frexp_ldexp() void = { + const tests64: [_]f64 = [INF, -INF, + 0.0, 1.0, -1.0, 2.42, 123456789.0, + F64_MIN_NORMAL, F64_MAX_NORMAL, + 3.0e-310f64]; + for (let i = 0z; i < len(tests64); i += 1) { + const parts = frexpf64(tests64[i]); + const res64 = ldexpf64(parts.0, parts.1); + assert(res64 == tests64[i]); + }; + assert(ldexpf64(1f64, -1076i64) == 0f64); + assert(ldexpf64(-1f64, -1076i64) == -0f64); + assert(signf(ldexpf64(-1f64, -1076i64)) < 0); + assert(ldexpf64(2f64, 1024i64) == INF); + assert(ldexpf64(-2f64, 1024i64) == -INF); + + const tests32: [_]f32 = [INF, -INF, + 0.0, 1.0, -1.0, 2.42, 123456789.0, + F32_MIN_NORMAL, F32_MAX_NORMAL, + 3.0e-39f32]; + for (let i = 0z; i < len(tests32); i += 1) { + const parts = frexpf32(tests32[i]); + const res = ldexpf32(parts.0, parts.1); + assert(res == tests32[i]); + }; + assert(ldexpf32(1.0f32, -1076i32) == 0.0f32); + assert(ldexpf32(-1.0f32, -1076i32) == -0.0f32); + assert(signf(ldexpf32(-1.0f32, -1076i32)) < 0); + assert(ldexpf32(2.0f32, 1024i32) == INF); + assert(ldexpf32(-2.0f32, 1024i32) == -INF); +}; + +@test fn modfrac() void = { + // 64 + for (let idx = 0z; idx < len(TEST_INPUTS); idx += 1) { + let res = modfracf64(TEST_INPUTS[idx]); + assert(res.0 == TEST_MODFRAC[idx].0); + assert(isclose(res.1, TEST_MODFRAC[idx].1)); + }; + let res = modfracf64(1.75f64); + assert(res.0 == 1i64); + assert(res.1 == 0.75f64); + res = modfracf64(0.75f64); + assert(res.0 == 0i64); + assert(res.1 == 0.75f64); + res = modfracf64(-0.75f64); + assert(res.0 == -0i64); + assert(res.1 == -0.75f64); + res = modfracf64(0f64); + assert(res.0 == 0i64); + assert(res.1 == 0f64); + assert(signf(res.1) > 0); + res = modfracf64(-0f64); + assert(res.0 == -0i64); + assert(res.1 == -0f64); + assert(signf(res.1) < 0); + res = modfracf64(23.50f64); + assert(res.0 == 23i64); + assert(res.1 == 0.50f64); + + // 32 + let res = modfracf32(1.75f32); + assert(res.0 == 1i32); + assert(res.1 == 0.75f32); + res = modfracf32(0.75f32); + assert(res.0 == 0i32); + assert(res.1 == 0.75f32); + res = modfracf32(-0.75f32); + assert(res.0 == -0i32); + assert(res.1 == -0.75f32); + res = modfracf32(0.0f32); + assert(res.0 == 0i32); + assert(res.1 == 0.0f32); + assert(signf(res.1) > 0); + res = modfracf32(-0.0f32); + assert(res.0 == -0i32); + assert(res.1 == -0.0f32); + assert(signf(res.1) < 0); + res = modfracf32(23.50f32); + assert(res.0 == 23i32); + assert(res.1 == 0.50f32); +}; + +@test fn nextafter() void = { + let f = &f64frombits; + // from musl's testsuite + assert(nextafterf64(f(0xc0202239f3c6a8f1), f(0x40122484b9ef31f0)) == f(0xc0202239f3c6a8f0)); + assert(nextafterf64(f(0x401161868e18bc67), f(0xc021c6a6cdce75e8)) == f(0x401161868e18bc66)); + assert(nextafterf64(f(0xc020c34b3e01e6e7), f(0xc0061bde29e83f6d)) == f(0xc020c34b3e01e6e6)); + assert(nextafterf64(f(0xc01a206f0a19dcc4), f(0x40124527f7b576ac)) == f(0xc01a206f0a19dcc3)); + assert(nextafterf64(f(0x402288bbb0d6a1e6), f(0x40133edd910a3c01)) == f(0x402288bbb0d6a1e5)); + assert(nextafterf64(f(0xc019ccd8be03f495), f(0x3fe52fb12ef638a1)) == f(0xc019ccd8be03f494)); + assert(nextafterf64(f(0x401f6f80ed2eab44), f(0x3faab3ff8575b21d)) == f(0x401f6f80ed2eab43)); + assert(nextafterf64(f(0xbfe95882b433fad3), f(0x401eb4a2e7ce0693)) == f(0xbfe95882b433fad2)); + assert(nextafterf64(f(0x3fe3b3d617ae3c4a), f(0x40001860611d75e1)) == f(0x3fe3b3d617ae3c4b)); + assert(nextafterf64(f(0xbfe1e159e36313ee), f(0x3fa081bd34224213)) == f(0xbfe1e159e36313ed)); + + assert(nextafterf64(f(0xbfe1e159e36313ee), f(0xbfe1e159e36313ee)) == f(0xbfe1e159e36313ee)); + assert(nextafterf64(0.0f64, 1.0f64) == f(0x1)); + assert(nextafterf64(0.0f64, -1.0f64) == f(0x8000000000000001)); + assert(nextafterf64(-0.0f64, 1.0f64) == f(0x1)); + assert(nextafterf64(-0.0f64, -1.0f64) == f(0x8000000000000001)); + assert(nextafterf64(0.0f64, 0.0f64) == 0.0f64); + assert(nextafterf64(-0.0f64, 0.0f64) == 0.0f64); + assert(nextafterf64(0.0f64, -0.0f64) == -0.0f64); + assert(isnan(nextafterf64(1.0f64, NAN))); + assert(isnan(nextafterf64(NAN, -2f64))); + assert(isnan(nextafterf64(NAN, NAN))); + + let f = &f32frombits; + assert(nextafterf32(f(0xc10111d0), f(0x40912426)) == f(0xc10111cf)); + assert(nextafterf32(f(0x408b0c34), f(0xc10e3536)) == f(0x408b0c33)); + assert(nextafterf32(f(0xc1061a5a), f(0xc030def1)) == f(0xc1061a59)); + assert(nextafterf32(f(0xc0d10378), f(0x40922940)) == f(0xc0d10377)); + assert(nextafterf32(f(0x411445de), f(0x4099f6ed)) == f(0x411445dd)); + assert(nextafterf32(f(0xc0ce66c6), f(0x3f297d89)) == f(0xc0ce66c5)); + assert(nextafterf32(f(0x40fb7c07), f(0x3d559ffc)) == f(0x40fb7c06)); + assert(nextafterf32(f(0xbf4ac416), f(0x40f5a517)) == f(0xbf4ac415)); + assert(nextafterf32(f(0x3f1d9eb1), f(0x4000c303)) == f(0x3f1d9eb2)); + assert(nextafterf32(f(0xbf0f0acf), f(0x3d040dea)) == f(0xbf0f0ace)); + + assert(nextafterf32(f(0xbf0f0acf), f(0xbf0f0acf)) == f(0xbf0f0acf)); + assert(nextafterf32(0.0f32, 1.0f32) == f(0x1)); + assert(nextafterf32(0.0f32, -1.0f32) == f(0x80000001)); + assert(nextafterf32(-0.0f32, 1.0f32) == f(0x1)); + assert(nextafterf32(-0.0f32, -1.0f32) == f(0x80000001)); + assert(nextafterf32(0.0f32, 0.0f32) == 0.0f32); + assert(nextafterf32(-0.0f32, 0.0f32) == 0.0f32); + assert(nextafterf32(0.0f32, -0.0f32) == -0.0f32); + assert(isnan(nextafterf32(1.0f32, NAN))); + assert(isnan(nextafterf32(NAN, -2f32))); + assert(isnan(nextafterf32(NAN, NAN))); +}; + +@test fn nearbyint() void = { + // from musl's testsuite + let f = &f64frombits; + assert(nearbyintf64(f(0xc0202239f3c6a8f1)) == f(0xc020000000000000)); + assert(nearbyintf64(f(0x401161868e18bc67)) == f(0x4010000000000000)); + assert(nearbyintf64(f(0xc020c34b3e01e6e7)) == f(0xc020000000000000)); + assert(nearbyintf64(f(0xc01a206f0a19dcc4)) == f(0xc01c000000000000)); + assert(nearbyintf64(f(0x402288bbb0d6a1e6)) == f(0x4022000000000000)); + assert(nearbyintf64(f(0x3fe52efd0cd80497)) == f(0x3ff0000000000000)); + assert(nearbyintf64(f(0xbfda05cc754481d1)) == f(0x8000000000000000)); + assert(nearbyintf64(f(0x3fe1f9ef934745cb)) == f(0x3ff0000000000000)); + assert(nearbyintf64(f(0x3fe8c5db097f7442)) == f(0x3ff0000000000000)); + assert(nearbyintf64(f(0xbfe5b86ea8118a0e)) == f(0xbff0000000000000)); + + let f = &f32frombits; + assert(nearbyintf32(f(0xc10111d0)) == f(0xc1000000)); + assert(nearbyintf32(f(0x408b0c34)) == f(0x40800000)); + assert(nearbyintf32(f(0xc1061a5a)) == f(0xc1000000)); + assert(nearbyintf32(f(0xc0d10378)) == f(0xc0e00000)); + assert(nearbyintf32(f(0x411445de)) == f(0x41100000)); + assert(nearbyintf32(f(0x3f2977e8)) == f(0x3f800000)); + assert(nearbyintf32(f(0xbed02e64)) == f(0x80000000)); + assert(nearbyintf32(f(0x3f0fcf7d)) == f(0x3f800000)); + assert(nearbyintf32(f(0x3f462ed8)) == f(0x3f800000)); + assert(nearbyintf32(f(0xbf2dc375)) == f(0xbf800000)); +}; diff --git a/math/+test/math.ha b/math/+test/math.ha @@ -0,0 +1,287 @@ +@test fn eqwithin() void = { + assert(eqwithin(1f64, 2f64, 2f64)); + assert(eqwithin(1.0f32, 2.0f32, 2.0f32)); + assert(!eqwithin(1.0005f32, 1.0004f32, 0.00001f32)); + assert(isclose(1f64, 1.0000000000000000000000000001f64)); + assert(isclose(1.0f32, 1.0000000000000000000000000001f32)); + assert(!isclose(1.0005f32, 1.0004f32)); +}; + +@test fn logf64() void = { + for (let idx = 0z; idx < len(TEST_INPUTS); idx += 1) { + assert(isclose( + logf64(absf64(TEST_INPUTS[idx])), + TEST_LOG[idx])); + }; + assert(logf64(E) == 1f64); + assert(logf64(54.598150033144239078110261202860878402790f64) == 4f64); + assert(isnan(logf64(-1f64))); + assert(logf64(INF) == INF); + assert(logf64(0f64) == -INF); + assert(isnan(logf64(NAN))); +}; + +@test fn log10f64() void = { + for (let idx = 0z; idx < len(TEST_INPUTS); idx += 1) { + assert(isclose( + log10f64(absf64(TEST_INPUTS[idx])), + TEST_LOG10[idx])); + }; +}; + +@test fn log2f64() void = { + for (let idx = 0z; idx < len(TEST_INPUTS); idx += 1) { + assert(isclose( + log2f64(absf64(TEST_INPUTS[idx])), + TEST_LOG2[idx])); + }; +}; + +@test fn log1p() void = { + for (let idx = 0z; idx < 10; idx += 1) { + assert(isclose( + log1pf64(TEST_INPUTS[idx] / 100f64), + TEST_LOG1P[idx])); + }; + assert(isnan(log1pf64(-INF))); + assert(isnan(log1pf64(-PI))); + assert(log1pf64(-1f64) == -INF); + assert(log1pf64(-0f64) == -0f64); + assert(log1pf64(0f64) == 0f64); + assert(log1pf64(INF) == INF); + assert(isnan(log1pf64(NAN))); +}; + +@test fn expf64() void = { + for (let idx = 0z; idx < len(TEST_INPUTS); idx += 1) { + assert(isclose(expf64(TEST_INPUTS[idx]), TEST_EXP[idx])); + }; + assert(expf64(1f64) == E); + assert(isnan(expf64(NAN))); + assert(isinf(expf64(INF))); + assert(expf64(-INF) == 0f64); + assert(isinf(expf64(99999f64))); + assert(expf64(-99999f64) == 0f64); + assert(expf64(0.5e-20) == 1f64); +}; + +@test fn exp2f64() void = { + for (let idx = 0z; idx < len(TEST_INPUTS); idx += 1) { + assert(isclose(exp2f64(TEST_INPUTS[idx]), TEST_EXP2[idx])); + }; + assert(exp2f64(0f64) == 1f64); + assert(exp2f64(3f64) == 8f64); + assert(exp2f64(-2f64) == 0.25f64); + assert(!isinf(exp2f64(256f64))); + assert(isinf(exp2f64(99999f64))); + assert(exp2f64(-99999f64) == 0f64); + assert(isnan(exp2f64(NAN))); + assert(isinf(exp2f64(INF))); + assert(exp2f64(-INF) == 0f64); +}; + +@test fn sqrt() void = { + for (let idx = 0z; idx < len(TEST_INPUTS); idx += 1) { + assert(isclose( + sqrtf64(absf64(TEST_INPUTS[idx])), + TEST_SQRT[idx])); + }; + assert(sqrtf64(2f64) == SQRT_2); + assert(sqrtf64(4f64) == 2f64); + assert(sqrtf64(16f64) == 4f64); + assert(sqrtf64(65536f64) == 256f64); + assert(sqrtf64(powf64(123f64, 2f64)) == 123f64); + assert(sqrtf64(0f64) == 0f64); + assert(isnan(sqrtf64(NAN))); + assert(sqrtf64(INF) == INF); + assert(isnan(sqrtf64(-2f64))); +}; + +@test fn powf64() void = { + for (let idx = 0z; idx < len(TEST_INPUTS); idx += 1) { + assert(eqwithin( + powf64(10f64, TEST_INPUTS[idx]), + TEST_POW[idx], + 1e-8f64)); + }; + // Positive integer + assert(powf64(2f64, 2f64) == 4f64); + assert(powf64(3f64, 3f64) == 27f64); + // Very large positive integer + assert(!isinf(powf64(2f64, 1020f64))); + assert(isinf(powf64(2f64, 1050f64))); + // Negative integer + assert(powf64(2f64, -1f64) == 0.5f64); + assert(powf64(2f64, -2f64) == 0.25f64); + // Very small negative integer + assert(powf64(2f64, -1020f64) > 0f64); + assert(powf64(2f64, -1080f64) == 0f64); + // Positive fractional powers + assert(eqwithin(powf64(2f64, 1.5f64), + 2.8284271247461900976033774f64, + 1e-10f64)); + assert(eqwithin(powf64(2f64, 5.5f64), + 45.254833995939041561654039f64, + 1e-10f64)); + // Negative fractional powers + assert(eqwithin(powf64(2f64, -1.5f64), + 0.3535533905932737622004221f64, + 1e-10f64)); + assert(eqwithin(powf64(2f64, -5.5f64), + 0.0220970869120796101375263f64, + 1e-10f64)); + + // Special cases + // pow(x, ±0) = 1 for any x + assert(powf64(123f64, 0f64) == 1f64); + // pow(1, y) = 1 for any y + assert(powf64(1f64, 123f64) == 1f64); + // pow(x, 1) = x for any x + assert(powf64(123f64, 1f64) == 123f64); + // pow(NaN, y) = NaN + assert(isnan(powf64(NAN, 123f64))); + // pow(x, NaN) = NaN + assert(isnan(powf64(123f64, NAN))); + // pow(±0, y) = ±Inf for y an odd integer < 0 + assert(powf64(0f64, -3f64) == INF); + assert(powf64(-0f64, -3f64) == -INF); + // pow(±0, -Inf) = +Inf + assert(powf64(0f64, -INF) == INF); + assert(powf64(-0f64, -INF) == INF); + // pow(±0, +Inf) = +0 + assert(powf64(0f64, INF) == 0f64); + assert(powf64(-0f64, INF) == 0f64); + // pow(±0, y) = +Inf for finite y < 0 and not an odd integer + assert(powf64(0f64, -2f64) == INF); + assert(powf64(0f64, -2f64) == INF); + //pow(±0, y) = ±0 for y an odd integer > 0 + assert(powf64(0f64, 123f64) == 0f64); + const neg_zero = powf64(-0f64, 123f64); + assert(neg_zero == 0f64); + assert(isnegative(neg_zero)); + // pow(±0, y) = +0 for finite y > 0 and not an odd integer + assert(powf64(0f64, 8f64) == 0f64); + // pow(-1, ±Inf) = 1 + assert(powf64(-1f64, INF) == 1f64); + assert(powf64(-1f64, -INF) == 1f64); + // pow(x, +Inf) = +Inf for |x| > 1 + assert(powf64(123f64, INF) == INF); + // pow(x, -Inf) = +0 for |x| > 1 + assert(powf64(123f64, -INF) == 0f64); + // pow(x, +Inf) = +0 for |x| < 1 + assert(powf64(0.5f64, INF) == 0f64); + assert(powf64(-0.5f64, INF) == 0f64); + // pow(x, -Inf) = +Inf for |x| < 1 + assert(powf64(0.5f64, -INF) == INF); + assert(powf64(-0.5f64, -INF) == INF); + // pow(+Inf, y) = +Inf for y > 0 + assert(powf64(INF, 123f64) == INF); + // pow(+Inf, y) = +0 for y < 0 + assert(powf64(INF, -1f64) == 0f64); + // pow(-Inf, y) = pow(-0, -y) + assert(powf64(-INF, 123f64) == powf64(-0f64, -123f64)); + // pow(x, y) = NaN for finite x < 0 and finite non-integer y + assert(isnan(powf64(-2f64, 1.23f64))); + // sqrt + assert(powf64(4f64, 0.5f64) == sqrtf64(4f64)); + assert(powf64(4f64, 0.5f64) == 2f64); + assert(powf64(4f64, -0.5f64) == (1f64 / sqrtf64(4f64))); + assert(powf64(4f64, -0.5f64) == (1f64 / 2f64)); +}; + +@test fn floor() void = { + for (let idx = 0z; idx < 10; idx += 1) { + assert(isclose( + floorf64(TEST_INPUTS[idx]), + TEST_FLOOR[idx])); + }; + assert(floorf64(-INF) == -INF); + assert(floorf64(-0f64) == -0f64); + assert(floorf64(0f64) == 0f64); + assert(floorf64(INF) == INF); + assert(isnan(floorf64(NAN))); +}; + +@test fn ceil() void = { + for (let idx = 0z; idx < 10; idx += 1) { + assert(isclose( + ceilf64(TEST_INPUTS[idx]), + TEST_CEIL[idx])); + }; + assert(ceilf64(-INF) == -INF); + assert(ceilf64(-0f64) == -0f64); + assert(ceilf64(0f64) == 0f64); + assert(ceilf64(INF) == INF); + assert(isnan(ceilf64(NAN))); +}; + +@test fn trunc() void = { + for (let idx = 0z; idx < 10; idx += 1) { + assert(isclose( + truncf64(TEST_INPUTS[idx]), + TEST_TRUNC[idx])); + }; + assert(truncf64(-INF) == -INF); + assert(truncf64(-0f64) == -0f64); + assert(truncf64(0f64) == 0f64); + assert(truncf64(INF) == INF); + assert(isnan(truncf64(NAN))); +}; + +@test fn round() void = { + for (let idx = 0z; idx < 10; idx += 1) { + assert(isclose( + roundf64(TEST_INPUTS[idx]), + TEST_ROUND[idx])); + }; + assert(roundf64(-INF) == -INF); + assert(roundf64(-0f64) == -0f64); + assert(roundf64(0f64) == 0f64); + assert(roundf64(INF) == INF); + assert(isnan(roundf64(NAN))); +}; + +@test fn modf64() void = { + for (let idx = 0z; idx < 10; idx += 1) { + assert(isclose( + modf64(10f64, TEST_INPUTS[idx]), + TEST_MODF[idx])); + }; + + assert(isnan(modf64(-INF, -INF))); + assert(isnan(modf64(-INF, -PI))); + assert(isnan(modf64(-INF, 0f64))); + assert(isnan(modf64(-INF, PI))); + assert(isnan(modf64(-INF, INF))); + assert(isnan(modf64(-INF, NAN))); + assert(modf64(-PI, -INF) == -PI); + assert(isnan(modf64(-PI, 0f64))); + assert(modf64(-PI, INF) == -PI); + assert(isnan(modf64(-PI, NAN))); + assert(modf64(-0f64, -INF) == -0f64); + assert(isnan(modf64(-0f64, 0f64))); + assert(modf64(-0f64, INF) == -0f64); + assert(isnan(modf64(-0f64, NAN))); + assert(modf64(0f64, -INF) == 0f64); + assert(isnan(modf64(0f64, 0f64))); + assert(modf64(0f64, INF) == 0f64); + assert(isnan(modf64(0f64, NAN))); + assert(modf64(PI, -INF) == PI); + assert(isnan(modf64(PI, 0f64))); + assert(modf64(PI, INF) == PI); + assert(isnan(modf64(PI, NAN))); + assert(isnan(modf64(INF, -INF))); + assert(isnan(modf64(INF, -PI))); + assert(isnan(modf64(INF, 0f64))); + assert(isnan(modf64(INF, PI))); + assert(isnan(modf64(INF, INF))); + assert(isnan(modf64(INF, NAN))); + assert(isnan(modf64(NAN, -INF))); + assert(isnan(modf64(NAN, -PI))); + assert(isnan(modf64(NAN, 0f64))); + assert(isnan(modf64(NAN, PI))); + assert(isnan(modf64(NAN, INF))); + assert(isnan(modf64(NAN, NAN))); + assert(modf64(5.9790119248836734e+200, 1.1258465975523544) == + 0.6447968302508578); +}; diff --git a/math/+test/trig.ha b/math/+test/trig.ha @@ -0,0 +1,220 @@ +@test fn trig_reduce() void = { + for (let idx = 0z; idx < 10; idx += 1) { + const reduced = trig_reduce(TEST_INPUTS[idx]); + const j = reduced.0; + const z = reduced.1; + const xred = (j: i64: f64) * (PI / 4f64) + z; + assert(isclose( + sinf64(TEST_INPUTS[idx]), + sinf64(xred))); + }; +}; + +@test fn cos() void = { + for (let idx = 0z; idx < 10; idx += 1) { + assert(isclose( + cosf64(TEST_INPUTS[idx]), TEST_COS[idx])); + }; + assert(isnan(cosf64(-INF))); + assert(isnan(cosf64(INF))); + assert(isnan(cosf64(NAN))); +}; + +@test fn sin() void = { + for (let idx = 0z; idx < 10; idx += 1) { + assert(isclose( + sinf64(TEST_INPUTS[idx]), TEST_SIN[idx])); + }; + assert(isnan(sinf64(-INF))); + assert(sinf64(-0f64) == -0f64); + assert(sinf64(0f64) == 0f64); + assert(isnan(sinf64(INF))); + assert(isnan(sinf64(NAN))); +}; + +@test fn tan() void = { + for (let idx = 0z; idx < 10; idx += 1) { + assert(isclose( + tanf64(TEST_INPUTS[idx]), TEST_TAN[idx])); + }; + assert(isnan(sinf64(-INF))); + assert(sinf64(-0f64) == -0f64); + assert(sinf64(0f64) == 0f64); + assert(isnan(sinf64(INF))); + assert(isnan(sinf64(NAN))); +}; + +@test fn asin() void = { + for (let idx = 0z; idx < 10; idx += 1) { + assert(isclose( + asinf64(TEST_INPUTS[idx] / 10f64), + TEST_ASIN[idx])); + }; + assert(isnan(asinf64(-PI))); + assert(asinf64(-0f64) == -0f64); + assert(asinf64(0f64) == 0f64); + assert(isnan(asinf64(PI))); + assert(isnan(asinf64(NAN))); +}; + +@test fn acos() void = { + for (let idx = 0z; idx < 10; idx += 1) { + assert(isclose( + acosf64(TEST_INPUTS[idx] / 10f64), + TEST_ACOS[idx])); + }; + assert(isnan(acosf64(-PI))); + assert(acosf64(1f64) == 0f64); + assert(isnan(acosf64(PI))); + assert(isnan(acosf64(NAN))); +}; + +@test fn atan() void = { + for (let idx = 0z; idx < 10; idx += 1) { + assert(isclose( + atanf64(TEST_INPUTS[idx]), + TEST_ATAN[idx])); + }; + assert(atanf64(-INF) == -PI / 2f64); + assert(atanf64(-0f64) == -0f64); + assert(atanf64(0f64) == 0f64); + assert(atanf64(INF) == PI / 2f64); + assert(isnan(atanf64(NAN))); +}; + +@test fn sinh() void = { + for (let idx = 0z; idx < 10; idx += 1) { + assert(eqwithin( + sinhf64(TEST_INPUTS[idx]), + TEST_SINH[idx], + 1e-6f64)); + }; + assert(sinhf64(-INF) == -INF); + assert(sinhf64(-0f64) == -0f64); + assert(sinhf64(0f64) == 0f64); + assert(sinhf64(INF) == INF); + assert(isnan(sinhf64(NAN))); +}; + +@test fn cosh() void = { + for (let idx = 0z; idx < 10; idx += 1) { + assert(isclose( + coshf64(TEST_INPUTS[idx]), + TEST_COSH[idx])); + }; + assert(coshf64(-INF) == INF); + assert(coshf64(-0f64) == 1f64); + assert(coshf64(0f64) == 1f64); + assert(coshf64(INF) == INF); + assert(isnan(coshf64(NAN))); +}; + +@test fn tanh() void = { + for (let idx = 0z; idx < 10; idx += 1) { + assert(isclose( + tanhf64(TEST_INPUTS[idx]), + TEST_TANH[idx])); + }; + assert(tanhf64(-INF) == -1f64); + assert(tanhf64(-0f64) == -0f64); + assert(tanhf64(0f64) == 0f64); + assert(tanhf64(INF) == 1f64); + assert(isnan(tanhf64(NAN))); +}; + +@test fn asinh() void = { + for (let idx = 0z; idx < 10; idx += 1) { + assert(isclose( + asinhf64(TEST_INPUTS[idx]), + TEST_ASINH[idx])); + }; + assert(asinhf64(-INF) == -INF); + assert(asinhf64(-0f64) == -0f64); + assert(asinhf64(0f64) == 0f64); + assert(asinhf64(INF) == INF); + assert(isnan(asinhf64(NAN))); +}; + +@test fn acosh() void = { + for (let idx = 0z; idx < 10; idx += 1) { + assert(isclose( + acoshf64(1f64 + absf64(TEST_INPUTS[idx])), + TEST_ACOSH[idx])); + }; + assert(isnan(acoshf64(-INF))); + assert(isnan(acoshf64(0.5f64))); + assert(acoshf64(1f64) == 0f64); + assert(acoshf64(INF) == INF); + assert(isnan(acoshf64(NAN))); +}; + +@test fn atanh() void = { + for (let idx = 0z; idx < 10; idx += 1) { + assert(isclose( + atanhf64(TEST_INPUTS[idx] / 10f64), + TEST_ATANH[idx])); + }; + assert(isnan(atanhf64(-INF))); + assert(isnan(atanhf64(-PI))); + assert(atanhf64(-1f64) == -INF); + assert(atanhf64(-0f64) == -0f64); + assert(atanhf64(0f64) == 0f64); + assert(atanhf64(1f64) == INF); + assert(isnan(atanhf64(PI))); + assert(isnan(atanhf64(INF))); + assert(isnan(atanhf64(NAN))); +}; + +@test fn atan2() void = { + for (let idx = 0z; idx < 10; idx += 1) { + assert(isclose( + atan2f64(10f64, TEST_INPUTS[idx]), + TEST_ATAN2[idx])); + }; + assert(isnan(atan2f64(-INF, NAN))); + assert(atan2f64(-PI, INF) == -0f64); + assert(isnan(atan2f64(-PI, NAN))); + assert(atan2f64(-0f64, 0f64) == -0f64); + assert(atan2f64(-0f64, PI) == -0f64); + assert(atan2f64(-0f64, INF) == -0f64); + assert(isnan(atan2f64(-0f64, NAN))); + assert(atan2f64(0f64, 0f64) == 0f64); + assert(atan2f64(0f64, PI) == 0f64); + assert(atan2f64(0f64, INF) == 0f64); + assert(isnan(atan2f64(0f64, NAN))); + assert(atan2f64(PI, INF) == 0f64); + assert(atan2f64(1f64, INF) == 0f64); + assert(atan2f64(-1f64, INF) == -0f64); + assert(isnan(atan2f64(PI, NAN))); + assert(isnan(atan2f64(INF, NAN))); + assert(isnan(atan2f64(NAN, NAN))); +}; + +@test fn hypot() void = { + for (let idx = 0z; idx < 10; idx += 1) { + const a = absf64(1e200f64 * TEST_TANH[idx] * SQRT_2); + assert(isclose( + hypotf64(1e200f64 * TEST_TANH[idx], + 1e200f64 * TEST_TANH[idx]), + a)); + }; + assert(hypotf64(-INF, -INF) == INF); + assert(hypotf64(-INF, 0f64) == INF); + assert(hypotf64(-INF, INF) == INF); + assert(hypotf64(-INF, NAN) == INF); + assert(hypotf64(-0f64, -0f64) == 0f64); + assert(hypotf64(-0f64, 0f64) == 0f64); + assert(hypotf64(0f64, -0f64) == 0f64); + assert(hypotf64(0f64, 0f64) == 0f64); + assert(hypotf64(0f64, -INF) == INF); + assert(hypotf64(0f64, INF) == INF); + assert(isnan(hypotf64(0f64, NAN))); + assert(hypotf64(INF, -INF) == INF); + assert(hypotf64(INF, 0f64) == INF); + assert(hypotf64(INF, INF) == INF); + assert(hypotf64(INF, NAN) == INF); + assert(hypotf64(NAN, -INF) == INF); + assert(isnan(hypotf64(NAN, 0f64))); + assert(hypotf64(NAN, INF) == INF); + assert(isnan(hypotf64(NAN, NAN))); +}; diff --git a/math/floats.ha b/math/floats.ha @@ -18,19 +18,6 @@ export fn f64frombits(n: u64) f64 = *(&n: *f64); // Returns f32 with the given binary representation. export fn f32frombits(n: u32) f32 = *(&n: *f32); -@test fn floatbits() void = { - const a: [_]f64 = [INF, -INF, 0.0, 1.0, -1.0, 123456789.0, - F64_MIN, F64_MIN_NORMAL, F64_MAX_NORMAL]; - for (let i = 0z; i < len(a); i += 1) { - assert(f64frombits(f64bits(a[i])) == a[i]); - }; - const a: [_]f32 = [INF, -INF, 0.0, 1.0, -1.0, -123456.0, - F32_MIN, F32_MIN_NORMAL, F32_MAX_NORMAL]; - for (let i = 0z; i < len(a); i += 1) { - assert(f32frombits(f32bits(a[i])) == a[i]); - }; -}; - // The number of bits in the significand of the binary representation of f64. export def F64_MANTISSA_BITS: u64 = 52; @@ -161,14 +148,6 @@ export def INF: f32 = 1.0 / 0.0; // Returns true if the given floating-point number is NaN. export fn isnan(n: f64) bool = n != n; -@test fn isnan() void = { - assert(isnan(NAN)); - assert(isnan(-NAN)); - assert(isnan(f64frombits(0xfffabcdef1234567))); - assert(!isnan(INF)); - assert(!isnan(1.23f32)); -}; - // Returns true if the given floating-point number is infinite. export fn isinf(n: f64) bool = { const bits = f64bits(n); @@ -237,50 +216,6 @@ export fn issubnormalf32(n: f32) bool = { return exp == 0 && mant != 0; }; -@test fn float_normality() void = { - assert(isnormal(0.0)); - assert(isnormal(1.0)); - assert(!isnormal(NAN)); - assert(!isnormal(INF)); - assert(!isnormal(1.0e-310)); - assert(!isnormal(1.0e-40f32)); - - assert(isnormalf32(1.0)); - assert(isnormalf32(0.0)); - assert(!isnormalf32(NAN)); - assert(!isnormalf32(INF)); - assert(!isnormalf32(-1.0e-40)); - assert(isnormalf32(-1.0e-50)); - - assert(isnormalf64(1.0)); - assert(isnormalf64(0.0)); - assert(!isnormalf64(NAN)); - assert(!isnormalf64(INF)); - assert(!isnormalf64(-1.0e-320)); - assert(isnormalf64(-1.0e-330)); - - assert(issubnormal(1.0e-320)); - assert(issubnormal(1.0e-42f32)); - assert(!issubnormal(NAN)); - assert(!issubnormal(INF)); - assert(!issubnormal(1.0)); - assert(!issubnormal(0.0)); - - assert(issubnormalf32(1.0e-45)); - assert(issubnormalf32(-1.0e-39)); - assert(!issubnormalf32(-NAN)); - assert(!issubnormalf32(-INF)); - assert(!issubnormalf32(0.0)); - assert(!issubnormalf32(-1.0e-49)); - - assert(issubnormalf64(5.0e-324)); - assert(issubnormalf64(-2.0e-310)); - assert(!issubnormalf64(-NAN)); - assert(!issubnormalf64(-INF)); - assert(!issubnormalf64(-1.0e-400)); - assert(!issubnormalf64(0.0)); -}; - // Returns the absolute value of f64 n. export fn absf64(n: f64) f64 = { if (isnan(n)) { @@ -307,20 +242,6 @@ export fn absf(n: types::floating) f64 = { }; }; -@test fn absf() void = { - for (let idx = 0z; idx < len(TEST_INPUTS); idx += 1) { - assert(absf(TEST_INPUTS[idx]) == TEST_ABSF[idx]); - }; - assert(absf64(2f64) == 2f64); - assert(absf32(2.0f32) == 2.0f32); - assert(absf(2f64) == 2f64); - assert(absf(2.0f32) == 2f64); - assert(absf(-2f64) == 2f64); - assert(absf(-2.0f32) == 2.0f32); - assert(absf(0f32) == 0f32); - assert(absf(0f64) == 0f64); -}; - // Returns 1 if x is positive and -1 if x is negative. Note that zero is also // signed. export fn signf64(x: f64) i64 = { @@ -352,22 +273,6 @@ export fn signf(x: types::floating) i64 = { }; }; -@test fn signf() void = { - for (let idx = 0z; idx < len(TEST_INPUTS); idx += 1) { - assert(signf(TEST_INPUTS[idx]) == TEST_SIGNF[idx]); - }; - assert(signf(0f64) == 1i64); - assert(signf(-0f64) == -1i64); - assert(signf(0.0f32) == 1i64); - assert(signf(-0.0f32) == -1i64); - assert(signf(1.5f64) == 1i64); - assert(signf(-1.5f64) == -1i64); - assert(ispositive(1f64)); - assert(!ispositive(-1f64)); - assert(isnegative(-1f64)); - assert(!isnegative(1f64)); -}; - // Returns whether or not x is positive. export fn ispositivef64(x: f64) bool = signf64(x) == 1i64; @@ -422,19 +327,6 @@ export fn copysign(x: types::floating, y: types::floating) f64 = { }; }; -@test fn copysign() void = { - assert(copysign(100f64, 1f64) == 100f64); - assert(copysign(100f64, -1f64) == -100f64); - assert(copysign(100.0f32, 1.0f32) == 100.0f32); - assert(copysign(100.0f32, -1.0f32) == -100.0f32); - assert(copysign(100f64, 0f64) == 100f64); - assert(copysign(100f64, -0f64) == -100f64); - assert(copysign(0f64, 100f64) == 0f64); - assert(signf(copysign(0f64, 100f64)) > 0); - assert(copysign(0f64, -100f64) == 0f64); - assert(signf(copysign(0f64, -100f64)) < 0); -}; - // Takes a potentially subnormal f64 n and returns a normal f64 normal_float // and an exponent exp such that n == normal_float * 2^{exp}. export fn normalizef64(n: f64) (f64, i64) = { @@ -457,15 +349,6 @@ export fn normalizef32(n: f32) (f64, i64) = { return (n, 0); }; -@test fn normalize() void = { - let res = normalizef64(5.0e-320); - assert(res.0 > F64_MIN_NORMAL); - assert(res.1 < 0i64); - res = normalizef64(5.0e-300); - assert(res.0 == 5.0e-300); - assert(res.1 == 0i64); -}; - // Breaks a f64 down into its mantissa and exponent. The mantissa will be // between 0.5 and 1. export fn frexpf64(n: f64) (f64, i64) = { @@ -514,25 +397,6 @@ export fn frexp(n: types::floating) (f64, i64) = { }; }; -@test fn frexp() void = { - for (let idx = 0z; idx < len(TEST_INPUTS); idx += 1) { - let res = frexp(TEST_INPUTS[idx]); - let expected = TEST_FREXP[idx]; - assert(res.0 == expected.0); - assert(res.1 == expected.1); - }; - let res = frexp(3f64); - assert(res.0 == 0.75f64); - assert(res.1 == 2i64); - res = frexp(2.42f64); - assert(res.0 == 0.605f64); - assert(res.1 == 2i64); - res = frexp(NAN); - assert(res.1 == 0); - res = frexp(INF); - assert(res.1 == 0); -}; - // Creates an f64 from a mantissa and an exponent. export fn ldexpf64(mantissa: f64, exp: i64) f64 = { if (isnan(mantissa) || isinf(mantissa) || mantissa == 0f64) { @@ -613,38 +477,6 @@ export fn ldexpf32(mantissa: f32, exp: i64) f32 = { return subnormal_factor * f32frombits(res); }; -@test fn frexp_ldexp() void = { - const tests64: [_]f64 = [INF, -INF, - 0.0, 1.0, -1.0, 2.42, 123456789.0, - F64_MIN_NORMAL, F64_MAX_NORMAL, - 3.0e-310f64]; - for (let i = 0z; i < len(tests64); i += 1) { - const parts = frexpf64(tests64[i]); - const res64 = ldexpf64(parts.0, parts.1); - assert(res64 == tests64[i]); - }; - assert(ldexpf64(1f64, -1076i64) == 0f64); - assert(ldexpf64(-1f64, -1076i64) == -0f64); - assert(signf(ldexpf64(-1f64, -1076i64)) < 0); - assert(ldexpf64(2f64, 1024i64) == INF); - assert(ldexpf64(-2f64, 1024i64) == -INF); - - const tests32: [_]f32 = [INF, -INF, - 0.0, 1.0, -1.0, 2.42, 123456789.0, - F32_MIN_NORMAL, F32_MAX_NORMAL, - 3.0e-39f32]; - for (let i = 0z; i < len(tests32); i += 1) { - const parts = frexpf32(tests32[i]); - const res = ldexpf32(parts.0, parts.1); - assert(res == tests32[i]); - }; - assert(ldexpf32(1.0f32, -1076i32) == 0.0f32); - assert(ldexpf32(-1.0f32, -1076i32) == -0.0f32); - assert(signf(ldexpf32(-1.0f32, -1076i32)) < 0); - assert(ldexpf32(2.0f32, 1024i32) == INF); - assert(ldexpf32(-2.0f32, 1024i32) == -INF); -}; - // Returns the integer and fractional parts of an f64. export fn modfracf64(n: f64) (i64, f64) = { if (n < 1f64) { @@ -699,56 +531,6 @@ export fn modfracf32(n: f32) (i32, f32) = { return ((int_part: i32), frac_part); }; -@test fn modfrac() void = { - // 64 - for (let idx = 0z; idx < len(TEST_INPUTS); idx += 1) { - let res = modfracf64(TEST_INPUTS[idx]); - assert(res.0 == TEST_MODFRAC[idx].0); - assert(isclose(res.1, TEST_MODFRAC[idx].1)); - }; - let res = modfracf64(1.75f64); - assert(res.0 == 1i64); - assert(res.1 == 0.75f64); - res = modfracf64(0.75f64); - assert(res.0 == 0i64); - assert(res.1 == 0.75f64); - res = modfracf64(-0.75f64); - assert(res.0 == -0i64); - assert(res.1 == -0.75f64); - res = modfracf64(0f64); - assert(res.0 == 0i64); - assert(res.1 == 0f64); - assert(signf(res.1) > 0); - res = modfracf64(-0f64); - assert(res.0 == -0i64); - assert(res.1 == -0f64); - assert(signf(res.1) < 0); - res = modfracf64(23.50f64); - assert(res.0 == 23i64); - assert(res.1 == 0.50f64); - - // 32 - let res = modfracf32(1.75f32); - assert(res.0 == 1i32); - assert(res.1 == 0.75f32); - res = modfracf32(0.75f32); - assert(res.0 == 0i32); - assert(res.1 == 0.75f32); - res = modfracf32(-0.75f32); - assert(res.0 == -0i32); - assert(res.1 == -0.75f32); - res = modfracf32(0.0f32); - assert(res.0 == 0i32); - assert(res.1 == 0.0f32); - assert(signf(res.1) > 0); - res = modfracf32(-0.0f32); - assert(res.0 == -0i32); - assert(res.1 == -0.0f32); - assert(signf(res.1) < 0); - res = modfracf32(23.50f32); - assert(res.0 == 23i32); - assert(res.1 == 0.50f32); -}; // Returns the f32 that is closest to 'x' in direction of 'y'. Returns NaN // if either parameter is NaN. Returns 'x' if both parameters are same. @@ -804,57 +586,6 @@ export fn nextafterf64(x: f64, y: f64) f64 = { return f64frombits(ux); }; -@test fn nextafter() void = { - let f = &f64frombits; - // from musl's testsuite - assert(nextafterf64(f(0xc0202239f3c6a8f1), f(0x40122484b9ef31f0)) == f(0xc0202239f3c6a8f0)); - assert(nextafterf64(f(0x401161868e18bc67), f(0xc021c6a6cdce75e8)) == f(0x401161868e18bc66)); - assert(nextafterf64(f(0xc020c34b3e01e6e7), f(0xc0061bde29e83f6d)) == f(0xc020c34b3e01e6e6)); - assert(nextafterf64(f(0xc01a206f0a19dcc4), f(0x40124527f7b576ac)) == f(0xc01a206f0a19dcc3)); - assert(nextafterf64(f(0x402288bbb0d6a1e6), f(0x40133edd910a3c01)) == f(0x402288bbb0d6a1e5)); - assert(nextafterf64(f(0xc019ccd8be03f495), f(0x3fe52fb12ef638a1)) == f(0xc019ccd8be03f494)); - assert(nextafterf64(f(0x401f6f80ed2eab44), f(0x3faab3ff8575b21d)) == f(0x401f6f80ed2eab43)); - assert(nextafterf64(f(0xbfe95882b433fad3), f(0x401eb4a2e7ce0693)) == f(0xbfe95882b433fad2)); - assert(nextafterf64(f(0x3fe3b3d617ae3c4a), f(0x40001860611d75e1)) == f(0x3fe3b3d617ae3c4b)); - assert(nextafterf64(f(0xbfe1e159e36313ee), f(0x3fa081bd34224213)) == f(0xbfe1e159e36313ed)); - - assert(nextafterf64(f(0xbfe1e159e36313ee), f(0xbfe1e159e36313ee)) == f(0xbfe1e159e36313ee)); - assert(nextafterf64(0.0f64, 1.0f64) == f(0x1)); - assert(nextafterf64(0.0f64, -1.0f64) == f(0x8000000000000001)); - assert(nextafterf64(-0.0f64, 1.0f64) == f(0x1)); - assert(nextafterf64(-0.0f64, -1.0f64) == f(0x8000000000000001)); - assert(nextafterf64(0.0f64, 0.0f64) == 0.0f64); - assert(nextafterf64(-0.0f64, 0.0f64) == 0.0f64); - assert(nextafterf64(0.0f64, -0.0f64) == -0.0f64); - assert(isnan(nextafterf64(1.0f64, NAN))); - assert(isnan(nextafterf64(NAN, -2f64))); - assert(isnan(nextafterf64(NAN, NAN))); - - let f = &f32frombits; - assert(nextafterf32(f(0xc10111d0), f(0x40912426)) == f(0xc10111cf)); - assert(nextafterf32(f(0x408b0c34), f(0xc10e3536)) == f(0x408b0c33)); - assert(nextafterf32(f(0xc1061a5a), f(0xc030def1)) == f(0xc1061a59)); - assert(nextafterf32(f(0xc0d10378), f(0x40922940)) == f(0xc0d10377)); - assert(nextafterf32(f(0x411445de), f(0x4099f6ed)) == f(0x411445dd)); - assert(nextafterf32(f(0xc0ce66c6), f(0x3f297d89)) == f(0xc0ce66c5)); - assert(nextafterf32(f(0x40fb7c07), f(0x3d559ffc)) == f(0x40fb7c06)); - assert(nextafterf32(f(0xbf4ac416), f(0x40f5a517)) == f(0xbf4ac415)); - assert(nextafterf32(f(0x3f1d9eb1), f(0x4000c303)) == f(0x3f1d9eb2)); - assert(nextafterf32(f(0xbf0f0acf), f(0x3d040dea)) == f(0xbf0f0ace)); - - assert(nextafterf32(f(0xbf0f0acf), f(0xbf0f0acf)) == f(0xbf0f0acf)); - assert(nextafterf32(0.0f32, 1.0f32) == f(0x1)); - assert(nextafterf32(0.0f32, -1.0f32) == f(0x80000001)); - assert(nextafterf32(-0.0f32, 1.0f32) == f(0x1)); - assert(nextafterf32(-0.0f32, -1.0f32) == f(0x80000001)); - assert(nextafterf32(0.0f32, 0.0f32) == 0.0f32); - assert(nextafterf32(-0.0f32, 0.0f32) == 0.0f32); - assert(nextafterf32(0.0f32, -0.0f32) == -0.0f32); - assert(isnan(nextafterf32(1.0f32, NAN))); - assert(isnan(nextafterf32(NAN, -2f32))); - assert(isnan(nextafterf32(NAN, NAN))); -}; - // Round a f32 to nearest integer value in floating point format fn nearbyintf32(x: f32) f32 = { let n = f32bits(x); @@ -892,30 +623,3 @@ fn nearbyintf64(x: f64) f64 = { else return y; }; - -@test fn nearbyint() void = { - // from musl's testsuite - let f = &f64frombits; - assert(nearbyintf64(f(0xc0202239f3c6a8f1)) == f(0xc020000000000000)); - assert(nearbyintf64(f(0x401161868e18bc67)) == f(0x4010000000000000)); - assert(nearbyintf64(f(0xc020c34b3e01e6e7)) == f(0xc020000000000000)); - assert(nearbyintf64(f(0xc01a206f0a19dcc4)) == f(0xc01c000000000000)); - assert(nearbyintf64(f(0x402288bbb0d6a1e6)) == f(0x4022000000000000)); - assert(nearbyintf64(f(0x3fe52efd0cd80497)) == f(0x3ff0000000000000)); - assert(nearbyintf64(f(0xbfda05cc754481d1)) == f(0x8000000000000000)); - assert(nearbyintf64(f(0x3fe1f9ef934745cb)) == f(0x3ff0000000000000)); - assert(nearbyintf64(f(0x3fe8c5db097f7442)) == f(0x3ff0000000000000)); - assert(nearbyintf64(f(0xbfe5b86ea8118a0e)) == f(0xbff0000000000000)); - - let f = &f32frombits; - assert(nearbyintf32(f(0xc10111d0)) == f(0xc1000000)); - assert(nearbyintf32(f(0x408b0c34)) == f(0x40800000)); - assert(nearbyintf32(f(0xc1061a5a)) == f(0xc1000000)); - assert(nearbyintf32(f(0xc0d10378)) == f(0xc0e00000)); - assert(nearbyintf32(f(0x411445de)) == f(0x41100000)); - assert(nearbyintf32(f(0x3f2977e8)) == f(0x3f800000)); - assert(nearbyintf32(f(0xbed02e64)) == f(0x80000000)); - assert(nearbyintf32(f(0x3f0fcf7d)) == f(0x3f800000)); - assert(nearbyintf32(f(0x3f462ed8)) == f(0x3f800000)); - assert(nearbyintf32(f(0xbf2dc375)) == f(0xbf800000)); -}; diff --git a/math/math.ha b/math/math.ha @@ -106,15 +106,6 @@ export fn isclose(x: types::floating, y: types::floating) bool = { }; }; -@test fn eqwithin() void = { - assert(eqwithin(1f64, 2f64, 2f64)); - assert(eqwithin(1.0f32, 2.0f32, 2.0f32)); - assert(!eqwithin(1.0005f32, 1.0004f32, 0.00001f32)); - assert(isclose(1f64, 1.0000000000000000000000000001f64)); - assert(isclose(1.0f32, 1.0000000000000000000000000001f32)); - assert(!isclose(1.0005f32, 1.0004f32)); -}; - // e - https://oeis.org/A001113 export def E: f64 = 2.71828182845904523536028747135266249775724709369995957496696763; // pi - https://oeis.org/A000796 @@ -231,33 +222,11 @@ export fn logf64(x: f64) f64 = { return k * LN2_HI - ((hfsq - (s * (hfsq + R) + k * LN2_LO)) - f); }; -@test fn logf64() void = { - for (let idx = 0z; idx < len(TEST_INPUTS); idx += 1) { - assert(isclose( - logf64(absf64(TEST_INPUTS[idx])), - TEST_LOG[idx])); - }; - assert(logf64(E) == 1f64); - assert(logf64(54.598150033144239078110261202860878402790f64) == 4f64); - assert(isnan(logf64(-1f64))); - assert(logf64(INF) == INF); - assert(logf64(0f64) == -INF); - assert(isnan(logf64(NAN))); -}; - // Returns the decimal logarithm of x. export fn log10f64(x: f64) f64 = { return logf64(x) * (1f64 / LN_10); }; -@test fn log10f64() void = { - for (let idx = 0z; idx < len(TEST_INPUTS); idx += 1) { - assert(isclose( - log10f64(absf64(TEST_INPUTS[idx])), - TEST_LOG10[idx])); - }; -}; - // Returns the binary logarithm of x. export fn log2f64(x: f64) f64 = { const frexp_res = frexpf64(x); @@ -271,14 +240,6 @@ export fn log2f64(x: f64) f64 = { return logf64(frac) * (1f64 / LN_2) + (exp: f64); }; -@test fn log2f64() void = { - for (let idx = 0z; idx < len(TEST_INPUTS); idx += 1) { - assert(isclose( - log2f64(absf64(TEST_INPUTS[idx])), - TEST_LOG2[idx])); - }; -}; - // double log1p(double x) // // Method : @@ -456,21 +417,6 @@ export fn log1pf64(x: f64) f64 = { ((hfsq - (s * (hfsq + R) + ((k: f64) * LN2LO + c))) - f); }; -@test fn log1p() void = { - for (let idx = 0z; idx < 10; idx += 1) { - assert(isclose( - log1pf64(TEST_INPUTS[idx] / 100f64), - TEST_LOG1P[idx])); - }; - assert(isnan(log1pf64(-INF))); - assert(isnan(log1pf64(-PI))); - assert(log1pf64(-1f64) == -INF); - assert(log1pf64(-0f64) == -0f64); - assert(log1pf64(0f64) == 0f64); - assert(log1pf64(INF) == INF); - assert(isnan(log1pf64(NAN))); -}; - // exp(x) // Returns the exponential of x. // @@ -611,34 +557,6 @@ export fn exp2f64(x: f64) f64 = { return expmultif64(hi, lo, k); }; -@test fn expf64() void = { - for (let idx = 0z; idx < len(TEST_INPUTS); idx += 1) { - assert(isclose(expf64(TEST_INPUTS[idx]), TEST_EXP[idx])); - }; - assert(expf64(1f64) == E); - assert(isnan(expf64(NAN))); - assert(isinf(expf64(INF))); - assert(expf64(-INF) == 0f64); - assert(isinf(expf64(99999f64))); - assert(expf64(-99999f64) == 0f64); - assert(expf64(0.5e-20) == 1f64); -}; - -@test fn exp2f64() void = { - for (let idx = 0z; idx < len(TEST_INPUTS); idx += 1) { - assert(isclose(exp2f64(TEST_INPUTS[idx]), TEST_EXP2[idx])); - }; - assert(exp2f64(0f64) == 1f64); - assert(exp2f64(3f64) == 8f64); - assert(exp2f64(-2f64) == 0.25f64); - assert(!isinf(exp2f64(256f64))); - assert(isinf(exp2f64(99999f64))); - assert(exp2f64(-99999f64) == 0f64); - assert(isnan(exp2f64(NAN))); - assert(isinf(exp2f64(INF))); - assert(exp2f64(-INF) == 0f64); -}; - // __ieee754_sqrt(x) // Return correctly rounded sqrt. // ----------------------------------------- @@ -761,23 +679,6 @@ export fn sqrtf64(x: f64) f64 = { return f64frombits(bits); }; -@test fn sqrt() void = { - for (let idx = 0z; idx < len(TEST_INPUTS); idx += 1) { - assert(isclose( - sqrtf64(absf64(TEST_INPUTS[idx])), - TEST_SQRT[idx])); - }; - assert(sqrtf64(2f64) == SQRT_2); - assert(sqrtf64(4f64) == 2f64); - assert(sqrtf64(16f64) == 4f64); - assert(sqrtf64(65536f64) == 256f64); - assert(sqrtf64(powf64(123f64, 2f64)) == 123f64); - assert(sqrtf64(0f64) == 0f64); - assert(isnan(sqrtf64(NAN))); - assert(sqrtf64(INF) == INF); - assert(isnan(sqrtf64(-2f64))); -}; - fn is_f64_odd_int(x: f64) bool = { const x_int_frac = modfracf64(x); const x_int = x_int_frac.0; @@ -887,98 +788,6 @@ export fn powf64(x: f64, p: f64) f64 = { return ldexpf64(res_mantissa, res_exp); }; -@test fn powf64() void = { - for (let idx = 0z; idx < len(TEST_INPUTS); idx += 1) { - assert(eqwithin( - powf64(10f64, TEST_INPUTS[idx]), - TEST_POW[idx], - 1e-8f64)); - }; - // Positive integer - assert(powf64(2f64, 2f64) == 4f64); - assert(powf64(3f64, 3f64) == 27f64); - // Very large positive integer - assert(!isinf(powf64(2f64, 1020f64))); - assert(isinf(powf64(2f64, 1050f64))); - // Negative integer - assert(powf64(2f64, -1f64) == 0.5f64); - assert(powf64(2f64, -2f64) == 0.25f64); - // Very small negative integer - assert(powf64(2f64, -1020f64) > 0f64); - assert(powf64(2f64, -1080f64) == 0f64); - // Positive fractional powers - assert(eqwithin(powf64(2f64, 1.5f64), - 2.8284271247461900976033774f64, - 1e-10f64)); - assert(eqwithin(powf64(2f64, 5.5f64), - 45.254833995939041561654039f64, - 1e-10f64)); - // Negative fractional powers - assert(eqwithin(powf64(2f64, -1.5f64), - 0.3535533905932737622004221f64, - 1e-10f64)); - assert(eqwithin(powf64(2f64, -5.5f64), - 0.0220970869120796101375263f64, - 1e-10f64)); - - // Special cases - // pow(x, ±0) = 1 for any x - assert(powf64(123f64, 0f64) == 1f64); - // pow(1, y) = 1 for any y - assert(powf64(1f64, 123f64) == 1f64); - // pow(x, 1) = x for any x - assert(powf64(123f64, 1f64) == 123f64); - // pow(NaN, y) = NaN - assert(isnan(powf64(NAN, 123f64))); - // pow(x, NaN) = NaN - assert(isnan(powf64(123f64, NAN))); - // pow(±0, y) = ±Inf for y an odd integer < 0 - assert(powf64(0f64, -3f64) == INF); - assert(powf64(-0f64, -3f64) == -INF); - // pow(±0, -Inf) = +Inf - assert(powf64(0f64, -INF) == INF); - assert(powf64(-0f64, -INF) == INF); - // pow(±0, +Inf) = +0 - assert(powf64(0f64, INF) == 0f64); - assert(powf64(-0f64, INF) == 0f64); - // pow(±0, y) = +Inf for finite y < 0 and not an odd integer - assert(powf64(0f64, -2f64) == INF); - assert(powf64(0f64, -2f64) == INF); - //pow(±0, y) = ±0 for y an odd integer > 0 - assert(powf64(0f64, 123f64) == 0f64); - const neg_zero = powf64(-0f64, 123f64); - assert(neg_zero == 0f64); - assert(isnegative(neg_zero)); - // pow(±0, y) = +0 for finite y > 0 and not an odd integer - assert(powf64(0f64, 8f64) == 0f64); - // pow(-1, ±Inf) = 1 - assert(powf64(-1f64, INF) == 1f64); - assert(powf64(-1f64, -INF) == 1f64); - // pow(x, +Inf) = +Inf for |x| > 1 - assert(powf64(123f64, INF) == INF); - // pow(x, -Inf) = +0 for |x| > 1 - assert(powf64(123f64, -INF) == 0f64); - // pow(x, +Inf) = +0 for |x| < 1 - assert(powf64(0.5f64, INF) == 0f64); - assert(powf64(-0.5f64, INF) == 0f64); - // pow(x, -Inf) = +Inf for |x| < 1 - assert(powf64(0.5f64, -INF) == INF); - assert(powf64(-0.5f64, -INF) == INF); - // pow(+Inf, y) = +Inf for y > 0 - assert(powf64(INF, 123f64) == INF); - // pow(+Inf, y) = +0 for y < 0 - assert(powf64(INF, -1f64) == 0f64); - // pow(-Inf, y) = pow(-0, -y) - assert(powf64(-INF, 123f64) == powf64(-0f64, -123f64)); - // pow(x, y) = NaN for finite x < 0 and finite non-integer y - assert(isnan(powf64(-2f64, 1.23f64))); - // sqrt - assert(powf64(4f64, 0.5f64) == sqrtf64(4f64)); - assert(powf64(4f64, 0.5f64) == 2f64); - assert(powf64(4f64, -0.5f64) == (1f64 / sqrtf64(4f64))); - assert(powf64(4f64, -0.5f64) == (1f64 / 2f64)); -}; - // Returns the greatest integer value less than or equal to x. export fn floorf64(x: f64) f64 = { if (x == 0f64 || isnan(x) || isinf(x)) { @@ -997,35 +806,9 @@ export fn floorf64(x: f64) f64 = { return (modfrac_res.0: f64); }; -@test fn floor() void = { - for (let idx = 0z; idx < 10; idx += 1) { - assert(isclose( - floorf64(TEST_INPUTS[idx]), - TEST_FLOOR[idx])); - }; - assert(floorf64(-INF) == -INF); - assert(floorf64(-0f64) == -0f64); - assert(floorf64(0f64) == 0f64); - assert(floorf64(INF) == INF); - assert(isnan(floorf64(NAN))); -}; - // Returns the least integer value greater than or equal to x. export fn ceilf64(x: f64) f64 = -floorf64(-x); -@test fn ceil() void = { - for (let idx = 0z; idx < 10; idx += 1) { - assert(isclose( - ceilf64(TEST_INPUTS[idx]), - TEST_CEIL[idx])); - }; - assert(ceilf64(-INF) == -INF); - assert(ceilf64(-0f64) == -0f64); - assert(ceilf64(0f64) == 0f64); - assert(ceilf64(INF) == INF); - assert(isnan(ceilf64(NAN))); -}; - // Returns the integer value of x. export fn truncf64(x: f64) f64 = { if (x == 0f64 || isnan(x) || isinf(x)) { @@ -1035,19 +818,6 @@ export fn truncf64(x: f64) f64 = { return (modfrac_res.0: f64); }; -@test fn trunc() void = { - for (let idx = 0z; idx < 10; idx += 1) { - assert(isclose( - truncf64(TEST_INPUTS[idx]), - TEST_TRUNC[idx])); - }; - assert(truncf64(-INF) == -INF); - assert(truncf64(-0f64) == -0f64); - assert(truncf64(0f64) == 0f64); - assert(truncf64(INF) == INF); - assert(isnan(truncf64(NAN))); -}; - // Returns the nearest integer, rounding half away from zero. export fn roundf64(x: f64) f64 = { let bits = f64bits(x); @@ -1071,19 +841,6 @@ export fn roundf64(x: f64) f64 = { return f64frombits(bits); }; -@test fn round() void = { - for (let idx = 0z; idx < 10; idx += 1) { - assert(isclose( - roundf64(TEST_INPUTS[idx]), - TEST_ROUND[idx])); - }; - assert(roundf64(-INF) == -INF); - assert(roundf64(-0f64) == -0f64); - assert(roundf64(0f64) == 0f64); - assert(roundf64(INF) == INF); - assert(isnan(roundf64(NAN))); -}; - // Returns the floating-point remainder of x / y. The magnitude of the result // is less than y and its sign agrees with that of x. export fn modf64(x: f64, y: f64) f64 = { @@ -1118,48 +875,3 @@ export fn modf64(x: f64, y: f64) f64 = { }; return r; }; - -@test fn modf64() void = { - for (let idx = 0z; idx < 10; idx += 1) { - assert(isclose( - modf64(10f64, TEST_INPUTS[idx]), - TEST_MODF[idx])); - }; - - assert(isnan(modf64(-INF, -INF))); - assert(isnan(modf64(-INF, -PI))); - assert(isnan(modf64(-INF, 0f64))); - assert(isnan(modf64(-INF, PI))); - assert(isnan(modf64(-INF, INF))); - assert(isnan(modf64(-INF, NAN))); - assert(modf64(-PI, -INF) == -PI); - assert(isnan(modf64(-PI, 0f64))); - assert(modf64(-PI, INF) == -PI); - assert(isnan(modf64(-PI, NAN))); - assert(modf64(-0f64, -INF) == -0f64); - assert(isnan(modf64(-0f64, 0f64))); - assert(modf64(-0f64, INF) == -0f64); - assert(isnan(modf64(-0f64, NAN))); - assert(modf64(0f64, -INF) == 0f64); - assert(isnan(modf64(0f64, 0f64))); - assert(modf64(0f64, INF) == 0f64); - assert(isnan(modf64(0f64, NAN))); - assert(modf64(PI, -INF) == PI); - assert(isnan(modf64(PI, 0f64))); - assert(modf64(PI, INF) == PI); - assert(isnan(modf64(PI, NAN))); - assert(isnan(modf64(INF, -INF))); - assert(isnan(modf64(INF, -PI))); - assert(isnan(modf64(INF, 0f64))); - assert(isnan(modf64(INF, PI))); - assert(isnan(modf64(INF, INF))); - assert(isnan(modf64(INF, NAN))); - assert(isnan(modf64(NAN, -INF))); - assert(isnan(modf64(NAN, -PI))); - assert(isnan(modf64(NAN, 0f64))); - assert(isnan(modf64(NAN, PI))); - assert(isnan(modf64(NAN, INF))); - assert(isnan(modf64(NAN, NAN))); - assert(modf64(5.9790119248836734e+200, 1.1258465975523544) == - 0.6447968302508578); -}; diff --git a/math/trig.ha b/math/trig.ha @@ -201,18 +201,6 @@ fn trig_reduce(x: f64) (u64, f64) = { return (j, z * PI4); }; -@test fn trig_reduce() void = { - for (let idx = 0z; idx < 10; idx += 1) { - const reduced = trig_reduce(TEST_INPUTS[idx]); - const j = reduced.0; - const z = reduced.1; - const xred = (j: i64: f64) * (PI / 4f64) + z; - assert(isclose( - sinf64(TEST_INPUTS[idx]), - sinf64(xred))); - }; -}; - // cos.c // // Circular cosine @@ -305,16 +293,6 @@ export fn cosf64(x: f64) f64 = { return y; }; -@test fn cos() void = { - for (let idx = 0z; idx < 10; idx += 1) { - assert(isclose( - cosf64(TEST_INPUTS[idx]), TEST_COS[idx])); - }; - assert(isnan(cosf64(-INF))); - assert(isnan(cosf64(INF))); - assert(isnan(cosf64(NAN))); -}; - // sin.c // // Circular sine @@ -416,18 +394,6 @@ export fn sinf64(x: f64) f64 = { return y; }; -@test fn sin() void = { - for (let idx = 0z; idx < 10; idx += 1) { - assert(isclose( - sinf64(TEST_INPUTS[idx]), TEST_SIN[idx])); - }; - assert(isnan(sinf64(-INF))); - assert(sinf64(-0f64) == -0f64); - assert(sinf64(0f64) == 0f64); - assert(isnan(sinf64(INF))); - assert(isnan(sinf64(NAN))); -}; - // tan.c // // Circular tangent @@ -527,18 +493,6 @@ export fn tanf64(x: f64) f64 = { return y; }; -@test fn tan() void = { - for (let idx = 0z; idx < 10; idx += 1) { - assert(isclose( - tanf64(TEST_INPUTS[idx]), TEST_TAN[idx])); - }; - assert(isnan(sinf64(-INF))); - assert(sinf64(-0f64) == -0f64); - assert(sinf64(0f64) == 0f64); - assert(isnan(sinf64(INF))); - assert(isnan(sinf64(NAN))); -}; - // Evaluates a series valid in the range [0, 0.66]. fn xatan(x: f64) f64 = { const P0 = -8.750608600031904122785e-01; @@ -602,36 +556,11 @@ export fn asinf64(x: f64) f64 = { return temp; }; -@test fn asin() void = { - for (let idx = 0z; idx < 10; idx += 1) { - assert(isclose( - asinf64(TEST_INPUTS[idx] / 10f64), - TEST_ASIN[idx])); - }; - assert(isnan(asinf64(-PI))); - assert(asinf64(-0f64) == -0f64); - assert(asinf64(0f64) == 0f64); - assert(isnan(asinf64(PI))); - assert(isnan(asinf64(NAN))); -}; - // Returns the arccosine, in radians, of x. export fn acosf64(x: f64) f64 = { return PI / 2f64 - asinf64(x); }; -@test fn acos() void = { - for (let idx = 0z; idx < 10; idx += 1) { - assert(isclose( - acosf64(TEST_INPUTS[idx] / 10f64), - TEST_ACOS[idx])); - }; - assert(isnan(acosf64(-PI))); - assert(acosf64(1f64) == 0f64); - assert(isnan(acosf64(PI))); - assert(isnan(acosf64(NAN))); -}; - // atan.c // Inverse circular tangent (arctangent) // @@ -663,19 +592,6 @@ export fn atanf64(x: f64) f64 = { return -satan(-x); }; -@test fn atan() void = { - for (let idx = 0z; idx < 10; idx += 1) { - assert(isclose( - atanf64(TEST_INPUTS[idx]), - TEST_ATAN[idx])); - }; - assert(atanf64(-INF) == -PI / 2f64); - assert(atanf64(-0f64) == -0f64); - assert(atanf64(0f64) == 0f64); - assert(atanf64(INF) == PI / 2f64); - assert(isnan(atanf64(NAN))); -}; - // Floating-point hyperbolic sine and cosine. // The exponential func is called for arguments greater in magnitude than 0.5. // A series is used for arguments smaller in magnitude than 0.5. @@ -717,20 +633,6 @@ export fn sinhf64(x: f64) f64 = { return temp; }; -@test fn sinh() void = { - for (let idx = 0z; idx < 10; idx += 1) { - assert(eqwithin( - sinhf64(TEST_INPUTS[idx]), - TEST_SINH[idx], - 1e-6f64)); - }; - assert(sinhf64(-INF) == -INF); - assert(sinhf64(-0f64) == -0f64); - assert(sinhf64(0f64) == 0f64); - assert(sinhf64(INF) == INF); - assert(isnan(sinhf64(NAN))); -}; - // Returns the hyperbolic cosine of x. export fn coshf64(x: f64) f64 = { x = absf64(x); @@ -741,19 +643,6 @@ export fn coshf64(x: f64) f64 = { return (ex + 1f64 / ex) * 0.5f64; }; -@test fn cosh() void = { - for (let idx = 0z; idx < 10; idx += 1) { - assert(isclose( - coshf64(TEST_INPUTS[idx]), - TEST_COSH[idx])); - }; - assert(coshf64(-INF) == INF); - assert(coshf64(-0f64) == 1f64); - assert(coshf64(0f64) == 1f64); - assert(coshf64(INF) == INF); - assert(isnan(coshf64(NAN))); -}; - // tanh.c // // Hyperbolic tangent @@ -819,19 +708,6 @@ export fn tanhf64(x: f64) f64 = { return z; }; -@test fn tanh() void = { - for (let idx = 0z; idx < 10; idx += 1) { - assert(isclose( - tanhf64(TEST_INPUTS[idx]), - TEST_TANH[idx])); - }; - assert(tanhf64(-INF) == -1f64); - assert(tanhf64(-0f64) == -0f64); - assert(tanhf64(0f64) == 0f64); - assert(tanhf64(INF) == 1f64); - assert(isnan(tanhf64(NAN))); -}; - // asinh(x) // Method : // Based on @@ -881,19 +757,6 @@ export fn asinhf64(x: f64) f64 = { return temp; }; -@test fn asinh() void = { - for (let idx = 0z; idx < 10; idx += 1) { - assert(isclose( - asinhf64(TEST_INPUTS[idx]), - TEST_ASINH[idx])); - }; - assert(asinhf64(-INF) == -INF); - assert(asinhf64(-0f64) == -0f64); - assert(asinhf64(0f64) == 0f64); - assert(asinhf64(INF) == INF); - assert(isnan(asinhf64(NAN))); -}; - // __ieee754_acosh(x) // Method : // Based on @@ -929,19 +792,6 @@ export fn acoshf64(x: f64) f64 = { return log1pf64(t + sqrtf64(2f64 * t + t * t)); }; -@test fn acosh() void = { - for (let idx = 0z; idx < 10; idx += 1) { - assert(isclose( - acoshf64(1f64 + absf64(TEST_INPUTS[idx])), - TEST_ACOSH[idx])); - }; - assert(isnan(acoshf64(-INF))); - assert(isnan(acoshf64(0.5f64))); - assert(acoshf64(1f64) == 0f64); - assert(acoshf64(INF) == INF); - assert(isnan(acoshf64(NAN))); -}; - // __ieee754_atanh(x) // Method : // 1. Reduce x to positive by atanh(-x) = -atanh(x) @@ -996,23 +846,6 @@ export fn atanhf64(x: f64) f64 = { return temp; }; -@test fn atanh() void = { - for (let idx = 0z; idx < 10; idx += 1) { - assert(isclose( - atanhf64(TEST_INPUTS[idx] / 10f64), - TEST_ATANH[idx])); - }; - assert(isnan(atanhf64(-INF))); - assert(isnan(atanhf64(-PI))); - assert(atanhf64(-1f64) == -INF); - assert(atanhf64(-0f64) == -0f64); - assert(atanhf64(0f64) == 0f64); - assert(atanhf64(1f64) == INF); - assert(isnan(atanhf64(PI))); - assert(isnan(atanhf64(INF))); - assert(isnan(atanhf64(NAN))); -}; - // Returns the arctangent, in radians, of y / x. export fn atan2f64(y: f64, x: f64) f64 = { if (isnan(y) || isnan(x)) { @@ -1041,31 +874,6 @@ export fn atan2f64(y: f64, x: f64) f64 = { return q; }; -@test fn atan2() void = { - for (let idx = 0z; idx < 10; idx += 1) { - assert(isclose( - atan2f64(10f64, TEST_INPUTS[idx]), - TEST_ATAN2[idx])); - }; - assert(isnan(atan2f64(-INF, NAN))); - assert(atan2f64(-PI, INF) == -0f64); - assert(isnan(atan2f64(-PI, NAN))); - assert(atan2f64(-0f64, 0f64) == -0f64); - assert(atan2f64(-0f64, PI) == -0f64); - assert(atan2f64(-0f64, INF) == -0f64); - assert(isnan(atan2f64(-0f64, NAN))); - assert(atan2f64(0f64, 0f64) == 0f64); - assert(atan2f64(0f64, PI) == 0f64); - assert(atan2f64(0f64, INF) == 0f64); - assert(isnan(atan2f64(0f64, NAN))); - assert(atan2f64(PI, INF) == 0f64); - assert(atan2f64(1f64, INF) == 0f64); - assert(atan2f64(-1f64, INF) == -0f64); - assert(isnan(atan2f64(PI, NAN))); - assert(isnan(atan2f64(INF, NAN))); - assert(isnan(atan2f64(NAN, NAN))); -}; - // Returns the square root of a*a + b*b, taking care to avoid unnecessary // overflow and underflow. export fn hypotf64(a: f64, b: f64) f64 = { @@ -1088,31 +896,3 @@ export fn hypotf64(a: f64, b: f64) f64 = { return a * sqrtf64(1f64 + b * b); }; -@test fn hypot() void = { - for (let idx = 0z; idx < 10; idx += 1) { - const a = absf64(1e200f64 * TEST_TANH[idx] * SQRT_2); - assert(isclose( - hypotf64(1e200f64 * TEST_TANH[idx], - 1e200f64 * TEST_TANH[idx]), - a)); - }; - assert(hypotf64(-INF, -INF) == INF); - assert(hypotf64(-INF, 0f64) == INF); - assert(hypotf64(-INF, INF) == INF); - assert(hypotf64(-INF, NAN) == INF); - assert(hypotf64(-0f64, -0f64) == 0f64); - assert(hypotf64(-0f64, 0f64) == 0f64); - assert(hypotf64(0f64, -0f64) == 0f64); - assert(hypotf64(0f64, 0f64) == 0f64); - assert(hypotf64(0f64, -INF) == INF); - assert(hypotf64(0f64, INF) == INF); - assert(isnan(hypotf64(0f64, NAN))); - assert(hypotf64(INF, -INF) == INF); - assert(hypotf64(INF, 0f64) == INF); - assert(hypotf64(INF, INF) == INF); - assert(hypotf64(INF, NAN) == INF); - assert(hypotf64(NAN, -INF) == INF); - assert(isnan(hypotf64(NAN, 0f64))); - assert(hypotf64(NAN, INF) == INF); - assert(isnan(hypotf64(NAN, NAN))); -}; diff --git a/scripts/gen-stdlib b/scripts/gen-stdlib @@ -972,7 +972,11 @@ math() { if [ $testing -eq 0 ]; then gensrcs_math else - gensrcs_math data+test.ha + gensrcs_math \ + +test/data.ha \ + +test/math.ha \ + +test/floats.ha \ + +test/trig.ha fi gen_ssa math types rt } diff --git a/stdlib.mk b/stdlib.mk @@ -3821,7 +3821,10 @@ testlib_math_any_srcs = \ $(STDLIB)/math/ints.ha \ $(STDLIB)/math/uints.ha \ $(STDLIB)/math/trig.ha \ - $(STDLIB)/math/data+test.ha + $(STDLIB)/math/+test/data.ha \ + $(STDLIB)/math/+test/math.ha \ + $(STDLIB)/math/+test/floats.ha \ + $(STDLIB)/math/+test/trig.ha $(TESTCACHE)/math/math-any.ssa: $(testlib_math_any_srcs) $(testlib_rt) $(testlib_types_$(PLATFORM)) $(testlib_rt_$(PLATFORM)) @printf 'HAREC \t$@\n'