diff options
| author | John Schmidt <john.schmidt.h@gmail.com> | 2022-02-04 20:21:15 +0100 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2022-02-09 20:29:41 -0500 |
| commit | 7f0cf395aa74eb5ea250bd28f7525b3036790a6a (patch) | |
| tree | e2faf4e4a19836331d3e47180438fab4db4fb178 /test/behavior/floatop.zig | |
| parent | 44b5fdf3266f11607313bc9990a876b5a7f9e174 (diff) | |
| download | zig-7f0cf395aa74eb5ea250bd28f7525b3036790a6a.tar.gz zig-7f0cf395aa74eb5ea250bd28f7525b3036790a6a.zip | |
stage2: implement all builtin floatops for f{16,32,64}
- Merge `floatop.zig` and `floatop_stage1.zig` since most tests now pass
on stage2.
- Add more behavior tests for a bunch of functions.
Diffstat (limited to 'test/behavior/floatop.zig')
| -rw-r--r-- | test/behavior/floatop.zig | 362 |
1 files changed, 349 insertions, 13 deletions
diff --git a/test/behavior/floatop.zig b/test/behavior/floatop.zig index 7807c690f6..ed632c26c5 100644 --- a/test/behavior/floatop.zig +++ b/test/behavior/floatop.zig @@ -1,12 +1,22 @@ const std = @import("std"); +const builtin = @import("builtin"); const expect = std.testing.expect; const math = std.math; const pi = std.math.pi; const e = std.math.e; const Vector = std.meta.Vector; +const has_f80_rt = @import("builtin").cpu.arch == .x86_64; +const epsilon_16 = 0.001; const epsilon = 0.000001; +fn epsForType(comptime T: type) T { + return switch (T) { + f16 => @as(f16, epsilon_16), + else => @as(T, epsilon), + }; +} + test "floating point comparisons" { try testFloatComparisons(); comptime try testFloatComparisons(); @@ -79,19 +89,37 @@ test "@sqrt" { } fn testSqrt() !void { - { - var a: f16 = 4; - try expect(@sqrt(a) == 2); - } - { - var a: f32 = 9; - try expect(@sqrt(a) == 3); - var b: f32 = 1.1; - try expect(math.approxEqAbs(f32, @sqrt(b), 1.0488088481701516, epsilon)); - } - { - var a: f64 = 25; - try expect(@sqrt(a) == 5); + try expect(@sqrt(@as(f16, 4)) == 2); + try expect(@sqrt(@as(f32, 9)) == 3); + try expect(@sqrt(@as(f64, 25)) == 5); + try expect(math.approxEqAbs(f32, @sqrt(@as(f32, 1.1)), 1.0488088481701516, epsilon)); + try expect(math.approxEqAbs(f32, @sqrt(@as(f32, 2.0)), 1.4142135623730950, epsilon)); + + if (builtin.zig_backend == .stage1) { + if (has_f80_rt) { + var a: f80 = 25; + try expect(@sqrt(a) == 5); + } + { + const a: comptime_float = 25.0; + try expect(@sqrt(a) == 5.0); + } + // TODO test f128, and c_longdouble + // https://github.com/ziglang/zig/issues/4026 + //{ + // var a: f128 = 49; + //try expect(@sqrt(a) == 7); + //} + + // TODO Implement Vector support for stage2 + { + var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 3.3, 4.4 }; + var result = @sqrt(v); + try expect(math.approxEqAbs(f32, @sqrt(@as(f32, 1.1)), result[0], epsilon)); + try expect(math.approxEqAbs(f32, @sqrt(@as(f32, 2.2)), result[1], epsilon)); + try expect(math.approxEqAbs(f32, @sqrt(@as(f32, 3.3)), result[2], epsilon)); + try expect(math.approxEqAbs(f32, @sqrt(@as(f32, 4.4)), result[3], epsilon)); + } } } @@ -114,3 +142,311 @@ test "more @sqrt f16 tests" { try expect(math.isNan(@sqrt(@as(f16, -1.0)))); try expect(math.isNan(@sqrt(@as(f16, math.nan(f16))))); } + +test "@sin" { + comptime try testSin(); + try testSin(); +} + +fn testSin() !void { + // TODO: Implement Vector support for other backends + if (builtin.zig_backend == .stage1) { + var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 3.3, 4.4 }; + var result = @sin(v); + try expect(math.approxEqAbs(f32, @sin(@as(f32, 1.1)), result[0], epsilon)); + try expect(math.approxEqAbs(f32, @sin(@as(f32, 2.2)), result[1], epsilon)); + try expect(math.approxEqAbs(f32, @sin(@as(f32, 3.3)), result[2], epsilon)); + try expect(math.approxEqAbs(f32, @sin(@as(f32, 4.4)), result[3], epsilon)); + + // stage1 emits an incorrect compile error for `@as(ty, std.math.pi / 2)` + // so skip the rest of the tests. + return; + } + + inline for ([_]type{ f16, f32, f64 }) |ty| { + const eps = epsForType(ty); + try expect(@sin(@as(ty, 0)) == 0); + try expect(math.approxEqAbs(ty, @sin(@as(ty, std.math.pi)), 0, eps)); + try expect(math.approxEqAbs(ty, @sin(@as(ty, std.math.pi / 2)), 1, eps)); + try expect(math.approxEqAbs(ty, @sin(@as(ty, std.math.pi / 4)), 0.7071067811865475, eps)); + } +} + +test "@cos" { + comptime try testCos(); + try testCos(); +} + +fn testCos() !void { + // TODO: Implement Vector support for other backends + if (builtin.zig_backend == .stage1) { + var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 3.3, 4.4 }; + var result = @cos(v); + try expect(math.approxEqAbs(f32, @cos(@as(f32, 1.1)), result[0], epsilon)); + try expect(math.approxEqAbs(f32, @cos(@as(f32, 2.2)), result[1], epsilon)); + try expect(math.approxEqAbs(f32, @cos(@as(f32, 3.3)), result[2], epsilon)); + try expect(math.approxEqAbs(f32, @cos(@as(f32, 4.4)), result[3], epsilon)); + + // stage1 emits an incorrect compile error for `@as(ty, std.math.pi / 2)` + // so skip the rest of the tests. + return; + } + + inline for ([_]type{ f16, f32, f64 }) |ty| { + const eps = epsForType(ty); + try expect(@cos(@as(ty, 0)) == 1); + try expect(math.approxEqAbs(ty, @cos(@as(ty, std.math.pi)), -1, eps)); + try expect(math.approxEqAbs(ty, @cos(@as(ty, std.math.pi / 2)), 0, eps)); + try expect(math.approxEqAbs(ty, @cos(@as(ty, std.math.pi / 4)), 0.7071067811865475, eps)); + } +} + +test "@exp" { + comptime try testExp(); + try testExp(); +} + +fn testExp() !void { + inline for ([_]type{ f16, f32, f64 }) |ty| { + const eps = epsForType(ty); + try expect(@exp(@as(ty, 0)) == 1); + try expect(math.approxEqAbs(ty, @exp(@as(ty, 2)), 7.389056098930650, eps)); + try expect(math.approxEqAbs(ty, @exp(@as(ty, 5)), 148.4131591025766, eps)); + } + + // TODO: Implement Vector support for other backends + if (builtin.zig_backend == .stage1) { + var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 0.3, 0.4 }; + var result = @exp(v); + try expect(math.approxEqAbs(f32, @exp(@as(f32, 1.1)), result[0], epsilon)); + try expect(math.approxEqAbs(f32, @exp(@as(f32, 2.2)), result[1], epsilon)); + try expect(math.approxEqAbs(f32, @exp(@as(f32, 0.3)), result[2], epsilon)); + try expect(math.approxEqAbs(f32, @exp(@as(f32, 0.4)), result[3], epsilon)); + } +} + +test "@exp2" { + comptime try testExp2(); + try testExp2(); +} + +fn testExp2() !void { + inline for ([_]type{ f16, f32, f64 }) |ty| { + const eps = epsForType(ty); + try expect(@exp2(@as(ty, 2)) == 4); + try expect(math.approxEqAbs(ty, @exp2(@as(ty, 1.5)), 2.8284271247462, eps)); + try expect(math.approxEqAbs(ty, @exp2(@as(ty, 4.5)), 22.627416997969, eps)); + } + + // TODO: Implement Vector support for other backends + if (builtin.zig_backend == .stage1) { + var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 0.3, 0.4 }; + var result = @exp2(v); + try expect(math.approxEqAbs(f32, @exp2(@as(f32, 1.1)), result[0], epsilon)); + try expect(math.approxEqAbs(f32, @exp2(@as(f32, 2.2)), result[1], epsilon)); + try expect(math.approxEqAbs(f32, @exp2(@as(f32, 0.3)), result[2], epsilon)); + try expect(math.approxEqAbs(f32, @exp2(@as(f32, 0.4)), result[3], epsilon)); + } +} + +test "@log" { + // Old musl (and glibc?), and our current math.ln implementation do not return 1 + // so also accept those values. + comptime try testLog(); + try testLog(); +} + +fn testLog() !void { + { + var a: f16 = e; + try expect(math.approxEqAbs(f16, @log(a), 1, epsilon)); + } + { + var a: f32 = e; + try expect(@log(a) == 1 or @log(a) == @bitCast(f32, @as(u32, 0x3f7fffff))); + } + { + var a: f64 = e; + try expect(@log(a) == 1 or @log(a) == @bitCast(f64, @as(u64, 0x3ff0000000000000))); + } + inline for ([_]type{ f16, f32, f64 }) |ty| { + const eps = epsForType(ty); + try expect(math.approxEqAbs(ty, @log(@as(ty, 2)), 0.6931471805599, eps)); + try expect(math.approxEqAbs(ty, @log(@as(ty, 5)), 1.6094379124341, eps)); + } + + // TODO: Implement Vector support for other backends + if (builtin.zig_backend == .stage1) { + var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 0.3, 0.4 }; + var result = @log(v); + try expect(math.approxEqAbs(f32, @log(@as(f32, 1.1)), result[0], epsilon)); + try expect(math.approxEqAbs(f32, @log(@as(f32, 2.2)), result[1], epsilon)); + try expect(math.approxEqAbs(f32, @log(@as(f32, 0.3)), result[2], epsilon)); + try expect(math.approxEqAbs(f32, @log(@as(f32, 0.4)), result[3], epsilon)); + } +} + +test "@log2" { + comptime try testLog2(); + try testLog2(); +} + +fn testLog2() !void { + inline for ([_]type{ f16, f32, f64 }) |ty| { + const eps = epsForType(ty); + try expect(@log2(@as(ty, 4)) == 2); + try expect(math.approxEqAbs(ty, @log2(@as(ty, 6)), 2.5849625007212, eps)); + try expect(math.approxEqAbs(ty, @log2(@as(ty, 10)), 3.3219280948874, eps)); + } + + // TODO: Implement Vector support for other backends + if (builtin.zig_backend == .stage1) { + var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 0.3, 0.4 }; + var result = @log2(v); + try expect(math.approxEqAbs(f32, @log2(@as(f32, 1.1)), result[0], epsilon)); + try expect(math.approxEqAbs(f32, @log2(@as(f32, 2.2)), result[1], epsilon)); + try expect(math.approxEqAbs(f32, @log2(@as(f32, 0.3)), result[2], epsilon)); + try expect(math.approxEqAbs(f32, @log2(@as(f32, 0.4)), result[3], epsilon)); + } +} + +test "@log10" { + comptime try testLog10(); + try testLog10(); +} + +fn testLog10() !void { + inline for ([_]type{ f16, f32, f64 }) |ty| { + const eps = epsForType(ty); + try expect(@log10(@as(ty, 100)) == 2); + try expect(math.approxEqAbs(ty, @log10(@as(ty, 15)), 1.176091259056, eps)); + try expect(math.approxEqAbs(ty, @log10(@as(ty, 50)), 1.698970004336, eps)); + } + + // TODO: Implement Vector support for other backends + if (builtin.zig_backend == .stage1) { + var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 0.3, 0.4 }; + var result = @log10(v); + try expect(math.approxEqAbs(f32, @log10(@as(f32, 1.1)), result[0], epsilon)); + try expect(math.approxEqAbs(f32, @log10(@as(f32, 2.2)), result[1], epsilon)); + try expect(math.approxEqAbs(f32, @log10(@as(f32, 0.3)), result[2], epsilon)); + try expect(math.approxEqAbs(f32, @log10(@as(f32, 0.4)), result[3], epsilon)); + } +} + +test "@fabs" { + comptime try testFabs(); + try testFabs(); +} + +fn testFabs() !void { + try expect(@fabs(@as(f16, -2.5)) == 2.5); + try expect(@fabs(@as(f16, 2.5)) == 2.5); + try expect(@fabs(@as(f32, -2.5)) == 2.5); + try expect(@fabs(@as(f32, 2.5)) == 2.5); + try expect(@fabs(@as(f64, -2.5)) == 2.5); + try expect(@fabs(@as(f64, 2.5)) == 2.5); + + // TODO test f128, and c_longdouble + // https://github.com/ziglang/zig/issues/4026 + // { + // var a: f80 = -2.5; + // var b: f80 = 2.5; + // try expect(@fabs(a) == 2.5); + // try expect(@fabs(b) == 2.5); + // } + + // TODO: Implement Vector support for other backends + if (builtin.zig_backend == .stage1) { + var v: Vector(4, f32) = [_]f32{ 1.1, -2.2, 0.3, -0.4 }; + var result = @fabs(v); + try expect(math.approxEqAbs(f32, @fabs(@as(f32, 1.1)), result[0], epsilon)); + try expect(math.approxEqAbs(f32, @fabs(@as(f32, -2.2)), result[1], epsilon)); + try expect(math.approxEqAbs(f32, @fabs(@as(f32, 0.3)), result[2], epsilon)); + try expect(math.approxEqAbs(f32, @fabs(@as(f32, -0.4)), result[3], epsilon)); + } +} + +test "@floor" { + comptime try testFloor(); + try testFloor(); +} + +fn testFloor() !void { + try expect(@floor(@as(f16, 2.1)) == 2); + try expect(@floor(@as(f32, 2.1)) == 2); + try expect(@floor(@as(f64, 3.5)) == 3); + + // TODO test f128, and c_longdouble + // https://github.com/ziglang/zig/issues/4026 + // { + // var a: f80 = 3.5; + // try expect(@floor(a) == 3); + // } + + // TODO: Implement Vector support for other backends + if (builtin.zig_backend == .stage1) { + var v: Vector(4, f32) = [_]f32{ 1.1, -2.2, 0.3, -0.4 }; + var result = @floor(v); + try expect(math.approxEqAbs(f32, @floor(@as(f32, 1.1)), result[0], epsilon)); + try expect(math.approxEqAbs(f32, @floor(@as(f32, -2.2)), result[1], epsilon)); + try expect(math.approxEqAbs(f32, @floor(@as(f32, 0.3)), result[2], epsilon)); + try expect(math.approxEqAbs(f32, @floor(@as(f32, -0.4)), result[3], epsilon)); + } +} + +test "@ceil" { + comptime try testCeil(); + try testCeil(); +} + +fn testCeil() !void { + try expect(@ceil(@as(f16, 2.1)) == 3); + try expect(@ceil(@as(f32, 2.1)) == 3); + try expect(@ceil(@as(f64, 3.5)) == 4); + + // TODO test f128, and c_longdouble + // https://github.com/ziglang/zig/issues/4026 + // { + // var a: f80 = 3.5; + // try expect(@ceil(a) == 4); + // } + + // TODO: Implement Vector support for other backends + if (builtin.zig_backend == .stage1) { + var v: Vector(4, f32) = [_]f32{ 1.1, -2.2, 0.3, -0.4 }; + var result = @ceil(v); + try expect(math.approxEqAbs(f32, @ceil(@as(f32, 1.1)), result[0], epsilon)); + try expect(math.approxEqAbs(f32, @ceil(@as(f32, -2.2)), result[1], epsilon)); + try expect(math.approxEqAbs(f32, @ceil(@as(f32, 0.3)), result[2], epsilon)); + try expect(math.approxEqAbs(f32, @ceil(@as(f32, -0.4)), result[3], epsilon)); + } +} + +test "@trunc" { + comptime try testTrunc(); + try testTrunc(); +} + +fn testTrunc() !void { + try expect(@trunc(@as(f16, 2.1)) == 2); + try expect(@trunc(@as(f32, 2.1)) == 2); + try expect(@trunc(@as(f64, -3.5)) == -3); + + // TODO test f128, and c_longdouble + // https://github.com/ziglang/zig/issues/4026 + // { + // var a: f80 = -3.5; + // try expect(@trunc(a) == -3); + // } + + // TODO: Implement Vector support for other backends + if (builtin.zig_backend == .stage1) { + var v: Vector(4, f32) = [_]f32{ 1.1, -2.2, 0.3, -0.4 }; + var result = @trunc(v); + try expect(math.approxEqAbs(f32, @trunc(@as(f32, 1.1)), result[0], epsilon)); + try expect(math.approxEqAbs(f32, @trunc(@as(f32, -2.2)), result[1], epsilon)); + try expect(math.approxEqAbs(f32, @trunc(@as(f32, 0.3)), result[2], epsilon)); + try expect(math.approxEqAbs(f32, @trunc(@as(f32, -0.4)), result[3], epsilon)); + } +} |
