Commit 6a3659c4e0

Robin Voetter <robin@voetter.nl>
2021-10-16 13:31:54
big.int: 2s-complement binary wrapping not
1 parent 98a37df
Changed files (2)
lib
std
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.
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();