big.int: 2s-complement binary wrapping not

This commit is contained in:
Robin Voetter 2021-10-16 13:31:54 +02:00
parent 98a37dfb23
commit 6a3659c4e0
2 changed files with 57 additions and 2 deletions

View File

@ -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.

View File

@ -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();