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 {
825825 ///
826826 /// Asserts there is enough memory to fit the result. The upper bound Limb count is
827827 /// 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 {
829829 // Special case: When the argument is negative, but the result is supposed to be unsigned,
830830 // return 0 in all cases.
831831 if (!a.positive and signedness == .unsigned) {
......@@ -906,6 +906,17 @@ pub const Mutable = struct {
906906 r.positive = a.positive;
907907 }
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
909920 /// r = a | b under 2s complement semantics.
910921 /// r may alias with a or b.
911922 ///
......@@ -2455,7 +2466,7 @@ pub const Managed = struct {
24552466 }
24562467
24572468 /// 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 {
24592470 try r.ensureTwosCompCapacity(bit_count);
24602471 var m = r.toMutable();
24612472 m.shiftLeftSat(a.toConst(), shift, signedness, bit_count);
......@@ -2476,6 +2487,14 @@ pub const Managed = struct {
24762487 r.setMetadata(m.positive, m.len);
24772488 }
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
24792498 /// r = a | b
24802499 ///
24812500 /// 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" {
18661866 try testing.expect((try a.to(SignedDoubleLimb)) == @as(SignedDoubleLimb, x) <<| shift);
18671867}
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
18691905test "big.int bitwise and simple" {
18701906 var a = try Managed.initSet(testing.allocator, 0xffffffff11111111);
18711907 defer a.deinit();