From 6a3659c4e005d9730fb824b77b416ef33200dbfe Mon Sep 17 00:00:00 2001 From: Robin Voetter Date: Sat, 16 Oct 2021 13:31:54 +0200 Subject: [PATCH] big.int: 2s-complement binary wrapping not --- lib/std/math/big/int.zig | 23 ++++++++++++++++++++-- lib/std/math/big/int_test.zig | 36 +++++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 2 deletions(-) diff --git a/lib/std/math/big/int.zig b/lib/std/math/big/int.zig index 8082e656e1..ddcda677d6 100644 --- a/lib/std/math/big/int.zig +++ b/lib/std/math/big/int.zig @@ -825,7 +825,7 @@ pub const Mutable = struct { /// /// Asserts there is enough memory to fit the result. The upper bound Limb count is /// r is `calcTwosCompLimbCount(bit_count)`. - pub fn shiftLeftSat(r: *Mutable, a: Const, shift: usize, signedness: std.builtin.Signedness, bit_count: usize) void { + pub fn shiftLeftSat(r: *Mutable, a: Const, shift: usize, signedness: Signedness, bit_count: usize) void { // Special case: When the argument is negative, but the result is supposed to be unsigned, // return 0 in all cases. if (!a.positive and signedness == .unsigned) { @@ -906,6 +906,17 @@ pub const Mutable = struct { r.positive = a.positive; } + /// r = ~a under 2s complement wrapping semantics. + /// r may alias with a. + /// + /// Assets that r has enough limbs to store the result. The upper bound Limb count is + /// r is `calcTwosCompLimbCount(bit_count)`. + pub fn bitNotWrap(r: *Mutable, a: Const, signedness: Signedness, bit_count: usize) void { + r.copy(a.negate()); + const negative_one = Const{ .limbs = &.{1}, .positive = false }; + r.addWrap(r.toConst(), negative_one, signedness, bit_count); + } + /// r = a | b under 2s complement semantics. /// r may alias with a or b. /// @@ -2455,7 +2466,7 @@ pub const Managed = struct { } /// r = a <<| shift with 2s-complement saturating semantics. - pub fn shiftLeftSat(r: *Managed, a: Managed, shift: usize, signedness: std.builtin.Signedness, bit_count: usize) !void { + pub fn shiftLeftSat(r: *Managed, a: Managed, shift: usize, signedness: Signedness, bit_count: usize) !void { try r.ensureTwosCompCapacity(bit_count); var m = r.toMutable(); m.shiftLeftSat(a.toConst(), shift, signedness, bit_count); @@ -2476,6 +2487,14 @@ pub const Managed = struct { r.setMetadata(m.positive, m.len); } + /// r = ~a under 2s-complement wrapping semantics. + pub fn bitNotWrap(r: *Managed, a: Managed, signedness: Signedness, bit_count: usize) !void { + try r.ensureTwosCompCapacity(bit_count); + var m = r.toMutable(); + m.bitNotWrap(a.toConst(), signedness, bit_count); + r.setMetadata(m.positive, m.len); + } + /// r = a | b /// /// a and b are zero-extended to the longer of a or b. diff --git a/lib/std/math/big/int_test.zig b/lib/std/math/big/int_test.zig index a7e3186632..78762d4fca 100644 --- a/lib/std/math/big/int_test.zig +++ b/lib/std/math/big/int_test.zig @@ -1866,6 +1866,42 @@ test "big.int sat shift-left signed multi negative" { try testing.expect((try a.to(SignedDoubleLimb)) == @as(SignedDoubleLimb, x) <<| shift); } +test "big.int bitNotWrap unsigned simple" { + var a = try Managed.initSet(testing.allocator, 123); + defer a.deinit(); + + try a.bitNotWrap(a, .unsigned, 10); + + try testing.expect((try a.to(u10)) == ~@as(u10, 123)); +} + +test "big.int bitNotWrap unsigned multi" { + var a = try Managed.initSet(testing.allocator, 0); + defer a.deinit(); + + try a.bitNotWrap(a, .unsigned, @bitSizeOf(DoubleLimb)); + + try testing.expect((try a.to(DoubleLimb)) == maxInt(DoubleLimb)); +} + +test "big.int bitNotWrap signed simple" { + 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)); +} + +test "big.int bitNotWrap signed multi" { + var a = try Managed.initSet(testing.allocator, 0); + defer a.deinit(); + + try a.bitNotWrap(a, .signed, @bitSizeOf(SignedDoubleLimb)); + + try testing.expect((try a.to(SignedDoubleLimb)) == -1); +} + test "big.int bitwise and simple" { var a = try Managed.initSet(testing.allocator, 0xffffffff11111111); defer a.deinit();