From a03f9548d3dd32876f99f5b7bdf1d678c5a5b98e Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Sun, 31 Jan 2021 20:58:11 +0100 Subject: [PATCH] std/math/big/int: normalize after a right shift After a right shift, top limbs may be all zero. However, without normalization, the number of limbs is not going to change. In order to check if a big number is zero, we used to assume that the number of limbs is 1. Which may not be the case after right shifts, even if the actual value is zero. - Normalize after a right shift - Add a test for that issue - Check all the limbs in `eqlZero()`. It may not be necessary if callers always remember to normalize before calling the function. But checking all the limbs is very cheap and makes the function less bug-prone. --- lib/std/math/big/int.zig | 8 +++++--- lib/std/math/big/int_test.zig | 6 ++++++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/lib/std/math/big/int.zig b/lib/std/math/big/int.zig index 3cd72dd8e4..81982eac51 100644 --- a/lib/std/math/big/int.zig +++ b/lib/std/math/big/int.zig @@ -549,8 +549,8 @@ pub const Mutable = struct { return; } - const r_len = llshr(r.limbs[0..], a.limbs[0..a.limbs.len], shift); - r.len = a.limbs.len - (shift / limb_bits); + llshr(r.limbs[0..], a.limbs[0..a.limbs.len], shift); + r.normalize(a.limbs.len - (shift / limb_bits)); r.positive = a.positive; } @@ -1348,7 +1348,9 @@ pub const Const = struct { /// Returns true if `a == 0`. pub fn eqZero(a: Const) bool { - return a.limbs.len == 1 and a.limbs[0] == 0; + var d: Limb = 0; + for (a.limbs) |limb| d |= limb; + return d == 0; } /// Returns true if `|a| == |b|`. diff --git a/lib/std/math/big/int_test.zig b/lib/std/math/big/int_test.zig index b73e9f90d6..179e55ff69 100644 --- a/lib/std/math/big/int_test.zig +++ b/lib/std/math/big/int_test.zig @@ -1287,6 +1287,12 @@ test "big.int shift-right multi" { try a.shiftRight(a, 67); testing.expect((try a.to(u64)) == 0x1fffe0001dddc222); + + try a.set(0xffff0000eeee1111dddd2222cccc3333); + try a.shiftRight(a, 63); + try a.shiftRight(a, 63); + try a.shiftRight(a, 2); + testing.expect(a.eqZero()); } test "big.int shift-left single" {