aboutsummaryrefslogtreecommitdiff
path: root/test/behavior/math.zig
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2022-01-29 14:25:43 -0700
committerAndrew Kelley <andrew@ziglang.org>2022-01-29 14:27:28 -0700
commitf8e418c47d13189674bdf5f131c19fd811964579 (patch)
tree7695c4d6ef606bae5f58c6a978b2f5642b298078 /test/behavior/math.zig
parent5e60ee41272579bc5fef3d95c59180df6ab824c1 (diff)
downloadzig-f8e418c47d13189674bdf5f131c19fd811964579.tar.gz
zig-f8e418c47d13189674bdf5f131c19fd811964579.zip
Sema: improved comptime `%` syntax
* comptime known 0 as a numerator returns comptime 0 independent of denominator. * negative numerator and denominator are allowed when the remainder is zero because that means the modulus would be also zero. * organize math behavior tests
Diffstat (limited to 'test/behavior/math.zig')
-rw-r--r--test/behavior/math.zig448
1 files changed, 448 insertions, 0 deletions
diff --git a/test/behavior/math.zig b/test/behavior/math.zig
index d7d75ef2ec..b75a4e17f7 100644
--- a/test/behavior/math.zig
+++ b/test/behavior/math.zig
@@ -1,3 +1,4 @@
+const builtin = @import("builtin");
const std = @import("std");
const expect = std.testing.expect;
const expectEqual = std.testing.expectEqual;
@@ -5,6 +6,7 @@ const expectEqualSlices = std.testing.expectEqualSlices;
const maxInt = std.math.maxInt;
const minInt = std.math.minInt;
const mem = std.mem;
+const has_f80_rt = builtin.cpu.arch == .x86_64;
test "assignment operators" {
var i: u32 = 0;
@@ -612,3 +614,449 @@ test "overflow arithmetic with u0 values" {
try expect(!@shlWithOverflow(u0, 0, 0, &result));
try expect(result == 0);
}
+
+test "allow signed integer division/remainder when values are comptime known and positive or exact" {
+ try expect(5 / 3 == 1);
+ try expect(-5 / -3 == 1);
+ try expect(-6 / 3 == -2);
+
+ try expect(5 % 3 == 2);
+ try expect(-6 % 3 == 0);
+
+ if (builtin.zig_backend != .stage1) {
+ var undef: i32 = undefined;
+ if (0 % undef != 0) {
+ @compileError("0 as numerator should return comptime zero independent of denominator");
+ }
+ }
+}
+
+test "quad hex float literal parsing accurate" {
+ if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
+
+ const a: f128 = 0x1.1111222233334444555566667777p+0;
+
+ // implied 1 is dropped, with an exponent of 0 (0x3fff) after biasing.
+ const expected: u128 = 0x3fff1111222233334444555566667777;
+ try expect(@bitCast(u128, a) == expected);
+
+ // non-normalized
+ const b: f128 = 0x11.111222233334444555566667777p-4;
+ try expect(@bitCast(u128, b) == expected);
+
+ const S = struct {
+ fn doTheTest() !void {
+ {
+ var f: f128 = 0x1.2eab345678439abcdefea56782346p+5;
+ try expect(@bitCast(u128, f) == 0x40042eab345678439abcdefea5678234);
+ }
+ {
+ var f: f128 = 0x1.edcb34a235253948765432134674fp-1;
+ try expect(@bitCast(u128, f) == 0x3ffeedcb34a235253948765432134674);
+ }
+ {
+ var f: f128 = 0x1.353e45674d89abacc3a2ebf3ff4ffp-50;
+ try expect(@bitCast(u128, f) == 0x3fcd353e45674d89abacc3a2ebf3ff50);
+ }
+ {
+ var f: f128 = 0x1.ed8764648369535adf4be3214567fp-9;
+ try expect(@bitCast(u128, f) == 0x3ff6ed8764648369535adf4be3214568);
+ }
+ const exp2ft = [_]f64{
+ 0x1.6a09e667f3bcdp-1,
+ 0x1.7a11473eb0187p-1,
+ 0x1.8ace5422aa0dbp-1,
+ 0x1.9c49182a3f090p-1,
+ 0x1.ae89f995ad3adp-1,
+ 0x1.c199bdd85529cp-1,
+ 0x1.d5818dcfba487p-1,
+ 0x1.ea4afa2a490dap-1,
+ 0x1.0000000000000p+0,
+ 0x1.0b5586cf9890fp+0,
+ 0x1.172b83c7d517bp+0,
+ 0x1.2387a6e756238p+0,
+ 0x1.306fe0a31b715p+0,
+ 0x1.3dea64c123422p+0,
+ 0x1.4bfdad5362a27p+0,
+ 0x1.5ab07dd485429p+0,
+ 0x1.8p23,
+ 0x1.62e430p-1,
+ 0x1.ebfbe0p-3,
+ 0x1.c6b348p-5,
+ 0x1.3b2c9cp-7,
+ 0x1.0p127,
+ -0x1.0p-149,
+ };
+
+ const answers = [_]u64{
+ 0x3fe6a09e667f3bcd,
+ 0x3fe7a11473eb0187,
+ 0x3fe8ace5422aa0db,
+ 0x3fe9c49182a3f090,
+ 0x3feae89f995ad3ad,
+ 0x3fec199bdd85529c,
+ 0x3fed5818dcfba487,
+ 0x3feea4afa2a490da,
+ 0x3ff0000000000000,
+ 0x3ff0b5586cf9890f,
+ 0x3ff172b83c7d517b,
+ 0x3ff2387a6e756238,
+ 0x3ff306fe0a31b715,
+ 0x3ff3dea64c123422,
+ 0x3ff4bfdad5362a27,
+ 0x3ff5ab07dd485429,
+ 0x4168000000000000,
+ 0x3fe62e4300000000,
+ 0x3fcebfbe00000000,
+ 0x3fac6b3480000000,
+ 0x3f83b2c9c0000000,
+ 0x47e0000000000000,
+ 0xb6a0000000000000,
+ };
+
+ for (exp2ft) |x, i| {
+ try expect(@bitCast(u64, x) == answers[i]);
+ }
+ }
+ };
+ try S.doTheTest();
+ comptime try S.doTheTest();
+}
+
+test "truncating shift left" {
+ if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
+
+ try testShlTrunc(maxInt(u16));
+ comptime try testShlTrunc(maxInt(u16));
+}
+fn testShlTrunc(x: u16) !void {
+ const shifted = x << 1;
+ try expect(shifted == 65534);
+}
+
+test "exact shift left" {
+ if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
+
+ try testShlExact(0b00110101);
+ comptime try testShlExact(0b00110101);
+}
+fn testShlExact(x: u8) !void {
+ const shifted = @shlExact(x, 2);
+ try expect(shifted == 0b11010100);
+}
+
+test "exact shift right" {
+ if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
+
+ try testShrExact(0b10110100);
+ comptime try testShrExact(0b10110100);
+}
+fn testShrExact(x: u8) !void {
+ const shifted = @shrExact(x, 2);
+ try expect(shifted == 0b00101101);
+}
+
+test "shift left/right on u0 operand" {
+ if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
+
+ const S = struct {
+ fn doTheTest() !void {
+ var x: u0 = 0;
+ var y: u0 = 0;
+ try expectEqual(@as(u0, 0), x << 0);
+ try expectEqual(@as(u0, 0), x >> 0);
+ try expectEqual(@as(u0, 0), x << y);
+ try expectEqual(@as(u0, 0), x >> y);
+ try expectEqual(@as(u0, 0), @shlExact(x, 0));
+ try expectEqual(@as(u0, 0), @shrExact(x, 0));
+ try expectEqual(@as(u0, 0), @shlExact(x, y));
+ try expectEqual(@as(u0, 0), @shrExact(x, y));
+ }
+ };
+ try S.doTheTest();
+ comptime try S.doTheTest();
+}
+
+test "comptime float rem int" {
+ if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
+
+ comptime {
+ var x = @as(f32, 1) % 2;
+ try expect(x == 1.0);
+ }
+}
+
+test "remainder division" {
+ if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
+
+ comptime try remdiv(f16);
+ comptime try remdiv(f32);
+ comptime try remdiv(f64);
+ comptime try remdiv(f128);
+ try remdiv(f16);
+ try remdiv(f64);
+ try remdiv(f128);
+}
+
+fn remdiv(comptime T: type) !void {
+ try expect(@as(T, 1) == @as(T, 1) % @as(T, 2));
+ try expect(@as(T, 1) == @as(T, 7) % @as(T, 3));
+}
+
+test "@sqrt" {
+ if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
+
+ try testSqrt(f64, 12.0);
+ comptime try testSqrt(f64, 12.0);
+ try testSqrt(f32, 13.0);
+ comptime try testSqrt(f32, 13.0);
+ try testSqrt(f16, 13.0);
+ comptime try testSqrt(f16, 13.0);
+
+ const x = 14.0;
+ const y = x * x;
+ const z = @sqrt(y);
+ comptime try expect(z == x);
+}
+
+fn testSqrt(comptime T: type, x: T) !void {
+ try expect(@sqrt(x * x) == x);
+}
+
+test "@fabs" {
+ if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
+
+ try testFabs(f128, 12.0);
+ comptime try testFabs(f128, 12.0);
+ if (has_f80_rt) try testFabs(f80, 12.0);
+ // comptime try testFabs(f80, 12.0);
+ try testFabs(f64, 12.0);
+ comptime try testFabs(f64, 12.0);
+ try testFabs(f32, 12.0);
+ comptime try testFabs(f32, 12.0);
+ try testFabs(f16, 12.0);
+ comptime try testFabs(f16, 12.0);
+
+ const x = 14.0;
+ const y = -x;
+ const z = @fabs(y);
+ comptime try expectEqual(x, z);
+}
+
+fn testFabs(comptime T: type, x: T) !void {
+ const y = -x;
+ const z = @fabs(y);
+ try expectEqual(x, z);
+}
+
+test "@floor" {
+ if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
+
+ // FIXME: Generates a floorl function call
+ // testFloor(f128, 12.0);
+ comptime try testFloor(f128, 12.0);
+ // try testFloor(f80, 12.0);
+ comptime try testFloor(f80, 12.0);
+ try testFloor(f64, 12.0);
+ comptime try testFloor(f64, 12.0);
+ try testFloor(f32, 12.0);
+ comptime try testFloor(f32, 12.0);
+ try testFloor(f16, 12.0);
+ comptime try testFloor(f16, 12.0);
+
+ const x = 14.0;
+ const y = x + 0.7;
+ const z = @floor(y);
+ comptime try expectEqual(x, z);
+}
+
+fn testFloor(comptime T: type, x: T) !void {
+ const y = x + 0.6;
+ const z = @floor(y);
+ try expectEqual(x, z);
+}
+
+test "@ceil" {
+ if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
+
+ // FIXME: Generates a ceill function call
+ //testCeil(f128, 12.0);
+ comptime try testCeil(f128, 12.0);
+ // try testCeil(f80, 12.0);
+ comptime try testCeil(f80, 12.0);
+ try testCeil(f64, 12.0);
+ comptime try testCeil(f64, 12.0);
+ try testCeil(f32, 12.0);
+ comptime try testCeil(f32, 12.0);
+ try testCeil(f16, 12.0);
+ comptime try testCeil(f16, 12.0);
+
+ const x = 14.0;
+ const y = x - 0.7;
+ const z = @ceil(y);
+ comptime try expectEqual(x, z);
+}
+
+fn testCeil(comptime T: type, x: T) !void {
+ const y = x - 0.8;
+ const z = @ceil(y);
+ try expectEqual(x, z);
+}
+
+test "@trunc" {
+ if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
+
+ // FIXME: Generates a truncl function call
+ //testTrunc(f128, 12.0);
+ comptime try testTrunc(f128, 12.0);
+ // try testTrunc(f80, 12.0);
+ // comptime try testTrunc(f80, 12.0);
+ comptime {
+ const x: f80 = 12.0;
+ const y = x + 0.8;
+ const z = @trunc(y);
+ try expectEqual(x, z);
+ }
+ try testTrunc(f64, 12.0);
+ comptime try testTrunc(f64, 12.0);
+ try testTrunc(f32, 12.0);
+ comptime try testTrunc(f32, 12.0);
+ try testTrunc(f16, 12.0);
+ comptime try testTrunc(f16, 12.0);
+
+ const x = 14.0;
+ const y = x + 0.7;
+ const z = @trunc(y);
+ comptime try expectEqual(x, z);
+}
+
+fn testTrunc(comptime T: type, x: T) !void {
+ {
+ const y = x + 0.8;
+ const z = @trunc(y);
+ try expectEqual(x, z);
+ }
+
+ {
+ const y = -x - 0.8;
+ const z = @trunc(y);
+ try expectEqual(-x, z);
+ }
+}
+
+test "@round" {
+ if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
+
+ // FIXME: Generates a roundl function call
+ //testRound(f128, 12.0);
+ comptime try testRound(f128, 12.0);
+ // try testRound(f80, 12.0);
+ comptime try testRound(f80, 12.0);
+ try testRound(f64, 12.0);
+ comptime try testRound(f64, 12.0);
+ try testRound(f32, 12.0);
+ comptime try testRound(f32, 12.0);
+ try testRound(f16, 12.0);
+ comptime try testRound(f16, 12.0);
+
+ const x = 14.0;
+ const y = x + 0.4;
+ const z = @round(y);
+ comptime try expectEqual(x, z);
+}
+
+fn testRound(comptime T: type, x: T) !void {
+ const y = x - 0.5;
+ const z = @round(y);
+ try expectEqual(x, z);
+}
+
+test "vector integer addition" {
+ if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
+
+ const S = struct {
+ fn doTheTest() !void {
+ var a: std.meta.Vector(4, i32) = [_]i32{ 1, 2, 3, 4 };
+ var b: std.meta.Vector(4, i32) = [_]i32{ 5, 6, 7, 8 };
+ var result = a + b;
+ var result_array: [4]i32 = result;
+ const expected = [_]i32{ 6, 8, 10, 12 };
+ try expectEqualSlices(i32, &expected, &result_array);
+ }
+ };
+ try S.doTheTest();
+ comptime try S.doTheTest();
+}
+
+test "NaN comparison" {
+ if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
+
+ try testNanEqNan(f16);
+ try testNanEqNan(f32);
+ try testNanEqNan(f64);
+ try testNanEqNan(f128);
+ if (has_f80_rt) try testNanEqNan(f80);
+ comptime try testNanEqNan(f16);
+ comptime try testNanEqNan(f32);
+ comptime try testNanEqNan(f64);
+ comptime try testNanEqNan(f128);
+ // comptime try testNanEqNan(f80);
+}
+
+fn testNanEqNan(comptime F: type) !void {
+ var nan1 = std.math.nan(F);
+ var nan2 = std.math.nan(F);
+ try expect(nan1 != nan2);
+ try expect(!(nan1 == nan2));
+ try expect(!(nan1 > nan2));
+ try expect(!(nan1 >= nan2));
+ try expect(!(nan1 < nan2));
+ try expect(!(nan1 <= nan2));
+}
+
+test "vector comparison" {
+ if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
+
+ const S = struct {
+ fn doTheTest() !void {
+ var a: std.meta.Vector(6, i32) = [_]i32{ 1, 3, -1, 5, 7, 9 };
+ var b: std.meta.Vector(6, i32) = [_]i32{ -1, 3, 0, 6, 10, -10 };
+ try expect(mem.eql(bool, &@as([6]bool, a < b), &[_]bool{ false, false, true, true, true, false }));
+ try expect(mem.eql(bool, &@as([6]bool, a <= b), &[_]bool{ false, true, true, true, true, false }));
+ try expect(mem.eql(bool, &@as([6]bool, a == b), &[_]bool{ false, true, false, false, false, false }));
+ try expect(mem.eql(bool, &@as([6]bool, a != b), &[_]bool{ true, false, true, true, true, true }));
+ try expect(mem.eql(bool, &@as([6]bool, a > b), &[_]bool{ true, false, false, false, false, true }));
+ try expect(mem.eql(bool, &@as([6]bool, a >= b), &[_]bool{ true, true, false, false, false, true }));
+ }
+ };
+ try S.doTheTest();
+ comptime try S.doTheTest();
+}
+
+test "compare undefined literal with comptime_int" {
+ if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
+
+ var x = undefined == 1;
+ // x is now undefined with type bool
+ x = true;
+ try expect(x);
+}
+
+test "signed zeros are represented properly" {
+ if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
+
+ const S = struct {
+ fn doTheTest() !void {
+ inline for ([_]type{ f16, f32, f64, f128 }) |T| {
+ const ST = std.meta.Int(.unsigned, @typeInfo(T).Float.bits);
+ var as_fp_val = -@as(T, 0.0);
+ var as_uint_val = @bitCast(ST, as_fp_val);
+ // Ensure the sign bit is set.
+ try expect(as_uint_val >> (@typeInfo(T).Float.bits - 1) == 1);
+ }
+ }
+ };
+
+ try S.doTheTest();
+ comptime try S.doTheTest();
+}