From 0b4461d97b5d315e71302f96076c54bbdffb7717 Mon Sep 17 00:00:00 2001 From: IntegratedQuantum <43880493+IntegratedQuantum@users.noreply.github.com> Date: Wed, 14 Dec 2022 01:29:25 +0100 Subject: [PATCH] Fix tautological big_int tests. --- lib/std/math/big/int.zig | 28 +++++++++++++--- lib/std/math/big/int_test.zig | 63 ++++++++++++++++++----------------- src/value.zig | 8 +++-- test/behavior.zig | 1 + test/behavior/bugs/13209.zig | 5 +++ 5 files changed, 68 insertions(+), 37 deletions(-) create mode 100644 test/behavior/bugs/13209.zig diff --git a/lib/std/math/big/int.zig b/lib/std/math/big/int.zig index 25b2ebc0a8..c301874451 100644 --- a/lib/std/math/big/int.zig +++ b/lib/std/math/big/int.zig @@ -1176,15 +1176,26 @@ pub const Mutable = struct { /// `a.limbs.len - (shift / (@sizeOf(Limb) * 8))`. pub fn shiftRight(r: *Mutable, a: Const, shift: usize) void { if (a.limbs.len <= shift / limb_bits) { - r.len = 1; - r.positive = true; - r.limbs[0] = 0; + // Shifting negative numbers converges to -1 instead of 0 + if (a.positive) { + r.len = 1; + r.positive = true; + r.limbs[0] = 0; + } else { + r.len = 1; + r.positive = false; + r.limbs[0] = 1; + } return; } llshr(r.limbs[0..], a.limbs[0..a.limbs.len], shift); r.normalize(a.limbs.len - (shift / limb_bits)); r.positive = a.positive; + // Shifting negative numbers converges to -1 instead of 0 + if (!r.positive and r.len == 1 and r.limbs[0] == 0) { + r.limbs[0] = 1; + } } /// r = ~a under 2s complement wrapping semantics. @@ -2974,8 +2985,15 @@ pub const Managed = struct { /// r and a may alias. pub fn shiftRight(r: *Managed, a: *const Managed, shift: usize) !void { if (a.len() <= shift / limb_bits) { - r.metadata = 1; - r.limbs[0] = 0; + // Shifting negative numbers converges to -1 instead of 0 + if (a.isPositive()) { + r.metadata = 1; + r.limbs[0] = 0; + } else { + r.metadata = 1; + r.setSign(false); + r.limbs[0] = 1; + } return; } diff --git a/lib/std/math/big/int_test.zig b/lib/std/math/big/int_test.zig index 13c7a5a352..fcd1196e99 100644 --- a/lib/std/math/big/int_test.zig +++ b/lib/std/math/big/int_test.zig @@ -516,8 +516,8 @@ test "big.int add multi-single" { } test "big.int add multi-multi" { - const op1 = 0xefefefef7f7f7f7f; - const op2 = 0xfefefefe9f9f9f9f; + var op1: u128 = 0xefefefef7f7f7f7f; + var op2: u128 = 0xfefefefe9f9f9f9f; var a = try Managed.initSet(testing.allocator, op1); defer a.deinit(); var b = try Managed.initSet(testing.allocator, op2); @@ -830,8 +830,8 @@ test "big.int sub multi-single" { } test "big.int sub multi-multi" { - const op1 = 0xefefefefefefefefefefefef; - const op2 = 0xabababababababababababab; + var op1: u128 = 0xefefefefefefefefefefefef; + var op2: u128 = 0xabababababababababababab; var a = try Managed.initSet(testing.allocator, op1); defer a.deinit(); @@ -914,8 +914,8 @@ test "big.int mul multi-single" { } test "big.int mul multi-multi" { - const op1 = 0x998888efefefefefefefef; - const op2 = 0x333000abababababababab; + var op1: u256 = 0x998888efefefefefefefef; + var op2: u256 = 0x333000abababababababab; var a = try Managed.initSet(testing.allocator, op1); defer a.deinit(); var b = try Managed.initSet(testing.allocator, op2); @@ -1033,8 +1033,8 @@ test "big.int mulWrap single-single signed" { } test "big.int mulWrap multi-multi unsigned" { - const op1 = 0x998888efefefefefefefef; - const op2 = 0x333000abababababababab; + var op1: u256 = 0x998888efefefefefefefef; + var op2: u256 = 0x333000abababababababab; var a = try Managed.initSet(testing.allocator, op1); defer a.deinit(); var b = try Managed.initSet(testing.allocator, op2); @@ -1044,7 +1044,7 @@ test "big.int mulWrap multi-multi unsigned" { defer c.deinit(); try c.mulWrap(&a, &b, .unsigned, 65); - try testing.expect((try c.to(u128)) == (op1 * op2) & ((1 << 65) - 1)); + try testing.expect((try c.to(u256)) == (op1 * op2) & ((1 << 65) - 1)); } test "big.int mulWrap multi-multi signed" { @@ -1150,8 +1150,8 @@ test "big.int div single-single with rem" { } test "big.int div multi-single no rem" { - const op1 = 0xffffeeeeddddcccc; - const op2 = 34; + var op1: u128 = 0xffffeeeeddddcccc; + var op2: u128 = 34; var a = try Managed.initSet(testing.allocator, op1); defer a.deinit(); @@ -1169,8 +1169,8 @@ test "big.int div multi-single no rem" { } test "big.int div multi-single with rem" { - const op1 = 0xffffeeeeddddcccf; - const op2 = 34; + var op1: u128 = 0xffffeeeeddddcccf; + var op2: u128 = 34; var a = try Managed.initSet(testing.allocator, op1); defer a.deinit(); @@ -1188,8 +1188,8 @@ test "big.int div multi-single with rem" { } test "big.int div multi>2-single" { - const op1 = 0xfefefefefefefefefefefefefefefefe; - const op2 = 0xefab8; + var op1: u128 = 0xfefefefefefefefefefefefefefefefe; + var op2: u128 = 0xefab8; var a = try Managed.initSet(testing.allocator, op1); defer a.deinit(); @@ -1981,22 +1981,22 @@ test "big.int shift-right negative" { var arg = try Managed.initSet(testing.allocator, -20); defer arg.deinit(); try a.shiftRight(&arg, 2); - try testing.expect((try a.to(i32)) == -20 >> 2); + try testing.expect((try a.to(i32)) == -5); // -20 >> 2 == -5 var arg2 = try Managed.initSet(testing.allocator, -5); defer arg2.deinit(); try a.shiftRight(&arg2, 10); - try testing.expect((try a.to(i32)) == -5 >> 10); + try testing.expect((try a.to(i32)) == -1); // -5 >> 10 == -1 } -test "big.int shift-left negative" { +test "big.int shift-right negative" { var a = try Managed.init(testing.allocator); defer a.deinit(); var arg = try Managed.initSet(testing.allocator, -10); defer arg.deinit(); try a.shiftRight(&arg, 1232); - try testing.expect((try a.to(i32)) == -10 >> 1232); + try testing.expect((try a.to(i32)) == -1); // -10 >> 1232 == -1 } test "big.int sat shift-left simple unsigned" { @@ -2064,34 +2064,35 @@ test "big.int sat shift-left signed simple positive" { } test "big.int sat shift-left signed multi positive" { - const x = 1; + var x: SignedDoubleLimb = 1; const shift = @bitSizeOf(SignedDoubleLimb) - 1; var a = try Managed.initSet(testing.allocator, x); defer a.deinit(); try a.shiftLeftSat(&a, shift, .signed, @bitSizeOf(SignedDoubleLimb)); - try testing.expect((try a.to(SignedDoubleLimb)) == @as(SignedDoubleLimb, x) <<| shift); + try testing.expect((try a.to(SignedDoubleLimb)) == x <<| shift); } test "big.int sat shift-left signed multi negative" { - const x = -1; + var x: SignedDoubleLimb = -1; const shift = @bitSizeOf(SignedDoubleLimb) - 1; var a = try Managed.initSet(testing.allocator, x); defer a.deinit(); try a.shiftLeftSat(&a, shift, .signed, @bitSizeOf(SignedDoubleLimb)); - try testing.expect((try a.to(SignedDoubleLimb)) == @as(SignedDoubleLimb, x) <<| shift); + try testing.expect((try a.to(SignedDoubleLimb)) == x <<| shift); } test "big.int bitNotWrap unsigned simple" { - var a = try Managed.initSet(testing.allocator, 123); + var x: u10 = 123; + var a = try Managed.initSet(testing.allocator, x); defer a.deinit(); try a.bitNotWrap(&a, .unsigned, 10); - try testing.expect((try a.to(u10)) == ~@as(u10, 123)); + try testing.expect((try a.to(u10)) == ~x); } test "big.int bitNotWrap unsigned multi" { @@ -2104,12 +2105,13 @@ test "big.int bitNotWrap unsigned multi" { } test "big.int bitNotWrap signed simple" { + var x: i11 = -456; var a = try Managed.initSet(testing.allocator, -456); defer a.deinit(); try a.bitNotWrap(&a, .signed, 11); - try testing.expect((try a.to(i11)) == ~@as(i11, -456)); + try testing.expect((try a.to(i11)) == ~x); } test "big.int bitNotWrap signed multi" { @@ -2232,14 +2234,16 @@ test "big.int bitwise xor simple" { } test "big.int bitwise xor multi-limb" { - var a = try Managed.initSet(testing.allocator, maxInt(Limb) + 1); + var x: DoubleLimb = maxInt(Limb) + 1; + var y: DoubleLimb = maxInt(Limb); + var a = try Managed.initSet(testing.allocator, x); defer a.deinit(); - var b = try Managed.initSet(testing.allocator, maxInt(Limb)); + var b = try Managed.initSet(testing.allocator, y); defer b.deinit(); try a.bitXor(&a, &b); - try testing.expect((try a.to(DoubleLimb)) == (maxInt(Limb) + 1) ^ maxInt(Limb)); + try testing.expect((try a.to(DoubleLimb)) == x ^ y); } test "big.int bitwise xor single negative simple" { @@ -2327,7 +2331,6 @@ test "big.int bitwise or multi-limb" { try a.bitOr(&a, &b); - // TODO: big.int.cpp or is wrong on multi-limb. try testing.expect((try a.to(DoubleLimb)) == (maxInt(Limb) + 1) + maxInt(Limb)); } diff --git a/src/value.zig b/src/value.zig index f37fec13bb..3d5636ee34 100644 --- a/src/value.zig +++ b/src/value.zig @@ -4194,8 +4194,12 @@ pub const Value = extern union { const result_limbs = lhs_bigint.limbs.len -| (shift / (@sizeOf(std.math.big.Limb) * 8)); if (result_limbs == 0) { // The shift is enough to remove all the bits from the number, which means the - // result is zero. - return Value.zero; + // result is 0 or -1 depending on the sign. + if (lhs_bigint.positive) { + return Value.zero; + } else { + return Value.negative_one; + } } const limbs = try allocator.alloc( diff --git a/test/behavior.zig b/test/behavior.zig index 55077d4ea2..ebd1e1afb7 100644 --- a/test/behavior.zig +++ b/test/behavior.zig @@ -125,6 +125,7 @@ test { _ = @import("behavior/bugs/13159.zig"); _ = @import("behavior/bugs/13164.zig"); _ = @import("behavior/bugs/13171.zig"); + _ = @import("behavior/bugs/13209.zig"); _ = @import("behavior/bugs/13285.zig"); _ = @import("behavior/bugs/13435.zig"); _ = @import("behavior/bugs/13664.zig"); diff --git a/test/behavior/bugs/13209.zig b/test/behavior/bugs/13209.zig new file mode 100644 index 0000000000..f85f0d342c --- /dev/null +++ b/test/behavior/bugs/13209.zig @@ -0,0 +1,5 @@ +const std = @import("std"); +test { + try std.testing.expect(-1 == @as(i8, -3) >> 2); + try std.testing.expect(-1 == -3 >> 2000); +}