authorgravatar for robin@voetter.nlRobin Voetter <robin@voetter.nl> 2021-10-16 13:31:54+02:00
committergravatar for robin@voetter.nlRobin Voetter <robin@voetter.nl> 2021-10-17 20:33:04+02:00
log6a3659c4e005d9730fb824b77b416ef33200dbfe
treeef23d2dfdfa3d053fad01ae284830c8c4f900f7e
parent98a37dfb23202e3f56e1596a19be3fa563f65eeb

big.int: 2s-complement binary wrapping not


2 files changed, 57 insertions(+), 2 deletions(-)

lib/std/math/big/int.zig+21-2
...@@ -825,7 +825,7 @@ pub const Mutable = struct {...@@ -825,7 +825,7 @@ pub const Mutable = struct {
825 ///825 ///
826 /// Asserts there is enough memory to fit the result. The upper bound Limb count is826 /// Asserts there is enough memory to fit the result. The upper bound Limb count is
827 /// r is `calcTwosCompLimbCount(bit_count)`.827 /// r is `calcTwosCompLimbCount(bit_count)`.
828 pub fn shiftLeftSat(r: *Mutable, a: Const, shift: usize, signedness: std.builtin.Signedness, bit_count: usize) void {828 pub fn shiftLeftSat(r: *Mutable, a: Const, shift: usize, signedness: Signedness, bit_count: usize) void {
829 // Special case: When the argument is negative, but the result is supposed to be unsigned,829 // Special case: When the argument is negative, but the result is supposed to be unsigned,
830 // return 0 in all cases.830 // return 0 in all cases.
831 if (!a.positive and signedness == .unsigned) {831 if (!a.positive and signedness == .unsigned) {
...@@ -906,6 +906,17 @@ pub const Mutable = struct {...@@ -906,6 +906,17 @@ pub const Mutable = struct {
906 r.positive = a.positive;906 r.positive = a.positive;
907 }907 }
908908
909 /// r = ~a under 2s complement wrapping semantics.
910 /// r may alias with a.
911 ///
912 /// Assets that r has enough limbs to store the result. The upper bound Limb count is
913 /// r is `calcTwosCompLimbCount(bit_count)`.
914 pub fn bitNotWrap(r: *Mutable, a: Const, signedness: Signedness, bit_count: usize) void {
915 r.copy(a.negate());
916 const negative_one = Const{ .limbs = &.{1}, .positive = false };
917 r.addWrap(r.toConst(), negative_one, signedness, bit_count);
918 }
919
909 /// r = a | b under 2s complement semantics.920 /// r = a | b under 2s complement semantics.
910 /// r may alias with a or b.921 /// r may alias with a or b.
911 ///922 ///
...@@ -2455,7 +2466,7 @@ pub const Managed = struct {...@@ -2455,7 +2466,7 @@ pub const Managed = struct {
2455 }2466 }
24562467
2457 /// r = a <<| shift with 2s-complement saturating semantics.2468 /// r = a <<| shift with 2s-complement saturating semantics.
2458 pub fn shiftLeftSat(r: *Managed, a: Managed, shift: usize, signedness: std.builtin.Signedness, bit_count: usize) !void {2469 pub fn shiftLeftSat(r: *Managed, a: Managed, shift: usize, signedness: Signedness, bit_count: usize) !void {
2459 try r.ensureTwosCompCapacity(bit_count);2470 try r.ensureTwosCompCapacity(bit_count);
2460 var m = r.toMutable();2471 var m = r.toMutable();
2461 m.shiftLeftSat(a.toConst(), shift, signedness, bit_count);2472 m.shiftLeftSat(a.toConst(), shift, signedness, bit_count);
...@@ -2476,6 +2487,14 @@ pub const Managed = struct {...@@ -2476,6 +2487,14 @@ pub const Managed = struct {
2476 r.setMetadata(m.positive, m.len);2487 r.setMetadata(m.positive, m.len);
2477 }2488 }
24782489
2490 /// r = ~a under 2s-complement wrapping semantics.
2491 pub fn bitNotWrap(r: *Managed, a: Managed, signedness: Signedness, bit_count: usize) !void {
2492 try r.ensureTwosCompCapacity(bit_count);
2493 var m = r.toMutable();
2494 m.bitNotWrap(a.toConst(), signedness, bit_count);
2495 r.setMetadata(m.positive, m.len);
2496 }
2497
2479 /// r = a | b2498 /// r = a | b
2480 ///2499 ///
2481 /// a and b are zero-extended to the longer of a or b.2500 /// a and b are zero-extended to the longer of a or b.
lib/std/math/big/int_test.zig+36
...@@ -1866,6 +1866,42 @@ test "big.int sat shift-left signed multi negative" {...@@ -1866,6 +1866,42 @@ test "big.int sat shift-left signed multi negative" {
1866 try testing.expect((try a.to(SignedDoubleLimb)) == @as(SignedDoubleLimb, x) <<| shift);1866 try testing.expect((try a.to(SignedDoubleLimb)) == @as(SignedDoubleLimb, x) <<| shift);
1867}1867}
18681868
1869test "big.int bitNotWrap unsigned simple" {
1870 var a = try Managed.initSet(testing.allocator, 123);
1871 defer a.deinit();
1872
1873 try a.bitNotWrap(a, .unsigned, 10);
1874
1875 try testing.expect((try a.to(u10)) == ~@as(u10, 123));
1876}
1877
1878test "big.int bitNotWrap unsigned multi" {
1879 var a = try Managed.initSet(testing.allocator, 0);
1880 defer a.deinit();
1881
1882 try a.bitNotWrap(a, .unsigned, @bitSizeOf(DoubleLimb));
1883
1884 try testing.expect((try a.to(DoubleLimb)) == maxInt(DoubleLimb));
1885}
1886
1887test "big.int bitNotWrap signed simple" {
1888 var a = try Managed.initSet(testing.allocator, -456);
1889 defer a.deinit();
1890
1891 try a.bitNotWrap(a, .signed, 11);
1892
1893 try testing.expect((try a.to(i11)) == ~@as(i11, -456));
1894}
1895
1896test "big.int bitNotWrap signed multi" {
1897 var a = try Managed.initSet(testing.allocator, 0);
1898 defer a.deinit();
1899
1900 try a.bitNotWrap(a, .signed, @bitSizeOf(SignedDoubleLimb));
1901
1902 try testing.expect((try a.to(SignedDoubleLimb)) == -1);
1903}
1904
1869test "big.int bitwise and simple" {1905test "big.int bitwise and simple" {
1870 var a = try Managed.initSet(testing.allocator, 0xffffffff11111111);1906 var a = try Managed.initSet(testing.allocator, 0xffffffff11111111);
1871 defer a.deinit();1907 defer a.deinit();