mirror of
https://codeberg.org/ziglang/zig.git
synced 2025-12-06 13:54:21 +00:00
Merge pull request #23310 from Rexicon226/fix-23309
big.int: return normalized results from `{add,sub}Carry`
This commit is contained in:
parent
cb3eec285f
commit
38ececf0a7
4 changed files with 53 additions and 5 deletions
|
|
@ -76,9 +76,18 @@ pub fn calcSqrtLimbsBufferLen(a_bit_count: usize) usize {
|
||||||
return a_limb_count + 3 * u_s_rem_limb_count + calcDivLimbsBufferLen(a_limb_count, u_s_rem_limb_count);
|
return a_limb_count + 3 * u_s_rem_limb_count + calcDivLimbsBufferLen(a_limb_count, u_s_rem_limb_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compute the number of limbs required to store a 2s-complement number of `bit_count` bits.
|
/// Compute the number of limbs required to store a 2s-complement number of `bit_count` bits.
|
||||||
|
pub fn calcNonZeroTwosCompLimbCount(bit_count: usize) usize {
|
||||||
|
assert(bit_count != 0);
|
||||||
|
return calcTwosCompLimbCount(bit_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Compute the number of limbs required to store a 2s-complement number of `bit_count` bits.
|
||||||
|
///
|
||||||
|
/// Special cases `bit_count == 0` to return 1. Zero-bit integers can only store the value zero
|
||||||
|
/// and this big integer implementation stores zero using one limb.
|
||||||
pub fn calcTwosCompLimbCount(bit_count: usize) usize {
|
pub fn calcTwosCompLimbCount(bit_count: usize) usize {
|
||||||
return std.math.divCeil(usize, bit_count, @bitSizeOf(Limb)) catch unreachable;
|
return @max(std.math.divCeil(usize, bit_count, @bitSizeOf(Limb)) catch unreachable, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// a + b * c + *carry, sets carry to the overflow bits
|
/// a + b * c + *carry, sets carry to the overflow bits
|
||||||
|
|
@ -188,8 +197,10 @@ pub const Mutable = struct {
|
||||||
if (self.limbs.ptr != other.limbs.ptr) {
|
if (self.limbs.ptr != other.limbs.ptr) {
|
||||||
@memcpy(self.limbs[0..other.limbs.len], other.limbs[0..other.limbs.len]);
|
@memcpy(self.limbs[0..other.limbs.len], other.limbs[0..other.limbs.len]);
|
||||||
}
|
}
|
||||||
self.positive = other.positive;
|
// Normalize before setting `positive` so the `eqlZero` doesn't need to iterate
|
||||||
self.len = other.limbs.len;
|
// over the extra zero limbs.
|
||||||
|
self.normalize(other.limbs.len);
|
||||||
|
self.positive = other.positive or other.eqlZero();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Efficiently swap an Mutable with another. This swaps the limb pointers and a full copy is not
|
/// Efficiently swap an Mutable with another. This swaps the limb pointers and a full copy is not
|
||||||
|
|
|
||||||
|
|
@ -726,6 +726,34 @@ test "subWrap single-multi, signed, limb aligned" {
|
||||||
try testing.expect((try a.toInt(SignedDoubleLimb)) == maxInt(SignedDoubleLimb));
|
try testing.expect((try a.toInt(SignedDoubleLimb)) == maxInt(SignedDoubleLimb));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test "addWrap returns normalized result" {
|
||||||
|
var x = try Managed.initSet(testing.allocator, 0);
|
||||||
|
defer x.deinit();
|
||||||
|
var y = try Managed.initSet(testing.allocator, 0);
|
||||||
|
defer y.deinit();
|
||||||
|
|
||||||
|
// make them both non normalized "-0"
|
||||||
|
x.setMetadata(false, 1);
|
||||||
|
y.setMetadata(false, 1);
|
||||||
|
|
||||||
|
var r = try Managed.init(testing.allocator);
|
||||||
|
defer r.deinit();
|
||||||
|
try testing.expect(!(try r.addWrap(&x, &y, .unsigned, 64)));
|
||||||
|
try testing.expect(r.isPositive() and r.len() == 1 and r.limbs[0] == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "subWrap returns normalized result" {
|
||||||
|
var x = try Managed.initSet(testing.allocator, 0);
|
||||||
|
defer x.deinit();
|
||||||
|
var y = try Managed.initSet(testing.allocator, 0);
|
||||||
|
defer y.deinit();
|
||||||
|
|
||||||
|
var r = try Managed.init(testing.allocator);
|
||||||
|
defer r.deinit();
|
||||||
|
try testing.expect(!(try r.subWrap(&x, &y, .unsigned, 64)));
|
||||||
|
try testing.expect(r.isPositive() and r.len() == 1 and r.limbs[0] == 0);
|
||||||
|
}
|
||||||
|
|
||||||
test "addSat single-single, unsigned" {
|
test "addSat single-single, unsigned" {
|
||||||
var a = try Managed.initSet(testing.allocator, maxInt(u17) - 5);
|
var a = try Managed.initSet(testing.allocator, maxInt(u17) - 5);
|
||||||
defer a.deinit();
|
defer a.deinit();
|
||||||
|
|
|
||||||
|
|
@ -2677,7 +2677,7 @@ pub fn shlSatScalar(
|
||||||
const shift: usize = @intCast(rhs.toUnsignedInt(zcu));
|
const shift: usize = @intCast(rhs.toUnsignedInt(zcu));
|
||||||
const limbs = try arena.alloc(
|
const limbs = try arena.alloc(
|
||||||
std.math.big.Limb,
|
std.math.big.Limb,
|
||||||
std.math.big.int.calcTwosCompLimbCount(info.bits) + 1,
|
std.math.big.int.calcTwosCompLimbCount(info.bits),
|
||||||
);
|
);
|
||||||
var result_bigint = BigIntMutable{
|
var result_bigint = BigIntMutable{
|
||||||
.limbs = limbs,
|
.limbs = limbs,
|
||||||
|
|
|
||||||
|
|
@ -535,3 +535,12 @@ test "return from inline for" {
|
||||||
};
|
};
|
||||||
try std.testing.expect(!S.do());
|
try std.testing.expect(!S.do());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test "for loop 0 length range" {
|
||||||
|
const map: []const u8 = &.{};
|
||||||
|
for (map, 0..map.len) |i, j| {
|
||||||
|
_ = i;
|
||||||
|
_ = j;
|
||||||
|
comptime unreachable;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue