Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions lib/std/math/big/int.zig
Original file line number Diff line number Diff line change
Expand Up @@ -2544,8 +2544,7 @@ pub const Const = struct {
const bits_per_limb = @bitSizeOf(Limb);
while (i != 0) {
i -= 1;
const limb = a.limbs[i];
const this_limb_lz = @clz(limb);
const this_limb_lz = @clz(a.limbs[i]);
total_limb_lz += this_limb_lz;
if (this_limb_lz != bits_per_limb) break;
}
Expand All @@ -2557,6 +2556,7 @@ pub const Const = struct {
pub fn ctz(a: Const, bits: Limb) Limb {
// Limbs are stored in little-endian order. Converting a negative number to twos-complement
// flips all bits above the lowest set bit, which does not affect the trailing zero count.
if (a.eqlZero()) return bits;
var result: Limb = 0;
for (a.limbs) |limb| {
const limb_tz = @ctz(limb);
Expand Down
224 changes: 224 additions & 0 deletions lib/std/math/big/int_test.zig
Original file line number Diff line number Diff line change
Expand Up @@ -3332,3 +3332,227 @@ test "(BigInt) negative" {
try testing.expect(mem.eql(u8, a_fmt, "(BigInt)"));
try testing.expect(!mem.eql(u8, b_fmt, "(BigInt)"));
}

test "clz" {
const neg_limb_max_squared: std.math.big.int.Const = .{
.limbs = &.{ 1, maxInt(Limb) - 1 },
.positive = false,
};
try testing.expect(neg_limb_max_squared.clz(@bitSizeOf(Limb) * 2 + 1) == 0);

const neg_limb_max_squared_plus_one: std.math.big.int.Const = .{
.limbs = &.{ 0, maxInt(Limb) - 1 },
.positive = false,
};
try testing.expect(neg_limb_max_squared_plus_one.clz(@bitSizeOf(Limb) * 2 + 1) == 0);

const neg_limb_msb_squared: std.math.big.int.Const = .{
.limbs = &.{ 0, 1 << @bitSizeOf(Limb) - 2 },
.positive = false,
};
try testing.expect(neg_limb_msb_squared.clz(@bitSizeOf(Limb) * 2) == 0);
try testing.expect(neg_limb_msb_squared.clz(@bitSizeOf(Limb) * 2 + 1) == 0);

const neg_limb_max: std.math.big.int.Const = .{
.limbs = &.{maxInt(Limb)},
.positive = false,
};
try testing.expect(neg_limb_max.clz(@bitSizeOf(Limb) + 1) == 0);
try testing.expect(neg_limb_max.clz(@bitSizeOf(Limb) * 2 - 1) == 0);
try testing.expect(neg_limb_max.clz(@bitSizeOf(Limb) * 2) == 0);
try testing.expect(neg_limb_max.clz(@bitSizeOf(Limb) * 2 + 1) == 0);

const neg_limb_msb: std.math.big.int.Const = .{
.limbs = &.{1 << @bitSizeOf(Limb) - 1},
.positive = false,
};
try testing.expect(neg_limb_msb.clz(@bitSizeOf(Limb)) == 0);
try testing.expect(neg_limb_msb.clz(@bitSizeOf(Limb) + 1) == 0);
try testing.expect(neg_limb_msb.clz(@bitSizeOf(Limb) * 2 - 1) == 0);
try testing.expect(neg_limb_msb.clz(@bitSizeOf(Limb) * 2) == 0);
try testing.expect(neg_limb_msb.clz(@bitSizeOf(Limb) * 2 + 1) == 0);

const neg_one: std.math.big.int.Const = .{
.limbs = &.{1},
.positive = false,
};
try testing.expect(neg_one.clz(@bitSizeOf(Limb)) == 0);
try testing.expect(neg_one.clz(@bitSizeOf(Limb) + 1) == 0);
try testing.expect(neg_one.clz(@bitSizeOf(Limb) * 2 - 1) == 0);
try testing.expect(neg_one.clz(@bitSizeOf(Limb) * 2) == 0);
try testing.expect(neg_one.clz(@bitSizeOf(Limb) * 2 + 1) == 0);

const zero: std.math.big.int.Const = .{
.limbs = &.{0},
.positive = true,
};
try testing.expect(zero.clz(@bitSizeOf(Limb)) == @bitSizeOf(Limb));
try testing.expect(zero.clz(@bitSizeOf(Limb) + 1) == @bitSizeOf(Limb) + 1);
try testing.expect(zero.clz(@bitSizeOf(Limb) * 2 - 1) == @bitSizeOf(Limb) * 2 - 1);
try testing.expect(zero.clz(@bitSizeOf(Limb) * 2) == @bitSizeOf(Limb) * 2);
try testing.expect(zero.clz(@bitSizeOf(Limb) * 2 + 1) == @bitSizeOf(Limb) * 2 + 1);

const one: std.math.big.int.Const = .{
.limbs = &.{1},
.positive = true,
};
try testing.expect(one.clz(@bitSizeOf(Limb)) == @bitSizeOf(Limb) - 1);
try testing.expect(one.clz(@bitSizeOf(Limb) + 1) == @bitSizeOf(Limb));
try testing.expect(one.clz(@bitSizeOf(Limb) * 2 - 1) == @bitSizeOf(Limb) * 2 - 2);
try testing.expect(one.clz(@bitSizeOf(Limb) * 2) == @bitSizeOf(Limb) * 2 - 1);
try testing.expect(one.clz(@bitSizeOf(Limb) * 2 + 1) == @bitSizeOf(Limb) * 2);

const limb_msb: std.math.big.int.Const = .{
.limbs = &.{1 << @bitSizeOf(Limb) - 1},
.positive = true,
};
try testing.expect(limb_msb.clz(@bitSizeOf(Limb)) == 0);
try testing.expect(limb_msb.clz(@bitSizeOf(Limb) + 1) == 1);
try testing.expect(limb_msb.clz(@bitSizeOf(Limb) * 2 - 1) == @bitSizeOf(Limb) - 1);
try testing.expect(limb_msb.clz(@bitSizeOf(Limb) * 2) == @bitSizeOf(Limb));
try testing.expect(limb_msb.clz(@bitSizeOf(Limb) * 2 + 1) == @bitSizeOf(Limb) + 1);

const limb_max: std.math.big.int.Const = .{
.limbs = &.{maxInt(Limb)},
.positive = true,
};
try testing.expect(limb_max.clz(@bitSizeOf(Limb)) == 0);
try testing.expect(limb_max.clz(@bitSizeOf(Limb) + 1) == 1);
try testing.expect(limb_max.clz(@bitSizeOf(Limb) * 2 - 1) == @bitSizeOf(Limb) - 1);
try testing.expect(limb_max.clz(@bitSizeOf(Limb) * 2) == @bitSizeOf(Limb));
try testing.expect(limb_max.clz(@bitSizeOf(Limb) * 2 + 1) == @bitSizeOf(Limb) + 1);

const limb_msb_squared: std.math.big.int.Const = .{
.limbs = &.{ 0, 1 << @bitSizeOf(Limb) - 2 },
.positive = true,
};
try testing.expect(limb_msb_squared.clz(@bitSizeOf(Limb) * 2 - 1) == 0);
try testing.expect(limb_msb_squared.clz(@bitSizeOf(Limb) * 2) == 1);
try testing.expect(limb_msb_squared.clz(@bitSizeOf(Limb) * 2 + 1) == 2);

const limb_max_squared_minus_one: std.math.big.int.Const = .{
.limbs = &.{ 0, maxInt(Limb) - 1 },
.positive = true,
};
try testing.expect(limb_max_squared_minus_one.clz(@bitSizeOf(Limb) * 2) == 0);
try testing.expect(limb_max_squared_minus_one.clz(@bitSizeOf(Limb) * 2 + 1) == 1);

const limb_max_squared: std.math.big.int.Const = .{
.limbs = &.{ 1, maxInt(Limb) - 1 },
.positive = true,
};
try testing.expect(limb_max_squared.clz(@bitSizeOf(Limb) * 2) == 0);
try testing.expect(limb_max_squared.clz(@bitSizeOf(Limb) * 2 + 1) == 1);
}

test "ctz" {
const neg_limb_max_squared: std.math.big.int.Const = .{
.limbs = &.{ 1, maxInt(Limb) - 1 },
.positive = false,
};
try testing.expect(neg_limb_max_squared.ctz(@bitSizeOf(Limb) * 2 + 1) == 0);

const neg_limb_max_squared_plus_one: std.math.big.int.Const = .{
.limbs = &.{ 0, maxInt(Limb) - 1 },
.positive = false,
};
try testing.expect(neg_limb_max_squared_plus_one.ctz(@bitSizeOf(Limb) * 2 + 1) == @bitSizeOf(Limb) + 1);

const neg_limb_msb_squared: std.math.big.int.Const = .{
.limbs = &.{ 0, 1 << @bitSizeOf(Limb) - 2 },
.positive = false,
};
try testing.expect(neg_limb_msb_squared.ctz(@bitSizeOf(Limb) * 2) == @bitSizeOf(Limb) * 2 - 2);
try testing.expect(neg_limb_msb_squared.ctz(@bitSizeOf(Limb) * 2 + 1) == @bitSizeOf(Limb) * 2 - 2);

const neg_limb_max: std.math.big.int.Const = .{
.limbs = &.{maxInt(Limb)},
.positive = false,
};
try testing.expect(neg_limb_max.ctz(@bitSizeOf(Limb) + 1) == 0);
try testing.expect(neg_limb_max.ctz(@bitSizeOf(Limb) * 2 - 1) == 0);
try testing.expect(neg_limb_max.ctz(@bitSizeOf(Limb) * 2) == 0);
try testing.expect(neg_limb_max.ctz(@bitSizeOf(Limb) * 2 + 1) == 0);

const neg_limb_msb: std.math.big.int.Const = .{
.limbs = &.{1 << @bitSizeOf(Limb) - 1},
.positive = false,
};
try testing.expect(neg_limb_msb.ctz(@bitSizeOf(Limb)) == @bitSizeOf(Limb) - 1);
try testing.expect(neg_limb_msb.ctz(@bitSizeOf(Limb) + 1) == @bitSizeOf(Limb) - 1);
try testing.expect(neg_limb_msb.ctz(@bitSizeOf(Limb) * 2 - 1) == @bitSizeOf(Limb) - 1);
try testing.expect(neg_limb_msb.ctz(@bitSizeOf(Limb) * 2) == @bitSizeOf(Limb) - 1);
try testing.expect(neg_limb_msb.ctz(@bitSizeOf(Limb) * 2 + 1) == @bitSizeOf(Limb) - 1);

const neg_one: std.math.big.int.Const = .{
.limbs = &.{1},
.positive = false,
};
try testing.expect(neg_one.ctz(@bitSizeOf(Limb)) == 0);
try testing.expect(neg_one.ctz(@bitSizeOf(Limb) + 1) == 0);
try testing.expect(neg_one.ctz(@bitSizeOf(Limb) * 2 - 1) == 0);
try testing.expect(neg_one.ctz(@bitSizeOf(Limb) * 2) == 0);
try testing.expect(neg_one.ctz(@bitSizeOf(Limb) * 2 + 1) == 0);

const zero: std.math.big.int.Const = .{
.limbs = &.{0},
.positive = true,
};
try testing.expect(zero.ctz(@bitSizeOf(Limb)) == @bitSizeOf(Limb));
try testing.expect(zero.ctz(@bitSizeOf(Limb) + 1) == @bitSizeOf(Limb) + 1);
try testing.expect(zero.ctz(@bitSizeOf(Limb) * 2 - 1) == @bitSizeOf(Limb) * 2 - 1);
try testing.expect(zero.ctz(@bitSizeOf(Limb) * 2) == @bitSizeOf(Limb) * 2);
try testing.expect(zero.ctz(@bitSizeOf(Limb) * 2 + 1) == @bitSizeOf(Limb) * 2 + 1);

const one: std.math.big.int.Const = .{
.limbs = &.{1},
.positive = true,
};
try testing.expect(one.ctz(@bitSizeOf(Limb)) == 0);
try testing.expect(one.ctz(@bitSizeOf(Limb) + 1) == 0);
try testing.expect(one.ctz(@bitSizeOf(Limb) * 2 - 1) == 0);
try testing.expect(one.ctz(@bitSizeOf(Limb) * 2) == 0);
try testing.expect(one.ctz(@bitSizeOf(Limb) * 2 + 1) == 0);

const limb_msb: std.math.big.int.Const = .{
.limbs = &.{1 << @bitSizeOf(Limb) - 1},
.positive = true,
};
try testing.expect(limb_msb.ctz(@bitSizeOf(Limb)) == @bitSizeOf(Limb) - 1);
try testing.expect(limb_msb.ctz(@bitSizeOf(Limb) + 1) == @bitSizeOf(Limb) - 1);
try testing.expect(limb_msb.ctz(@bitSizeOf(Limb) * 2 - 1) == @bitSizeOf(Limb) - 1);
try testing.expect(limb_msb.ctz(@bitSizeOf(Limb) * 2) == @bitSizeOf(Limb) - 1);
try testing.expect(limb_msb.ctz(@bitSizeOf(Limb) * 2 + 1) == @bitSizeOf(Limb) - 1);

const limb_max: std.math.big.int.Const = .{
.limbs = &.{maxInt(Limb)},
.positive = true,
};
try testing.expect(limb_max.ctz(@bitSizeOf(Limb)) == 0);
try testing.expect(limb_max.ctz(@bitSizeOf(Limb) + 1) == 0);
try testing.expect(limb_max.ctz(@bitSizeOf(Limb) * 2 - 1) == 0);
try testing.expect(limb_max.ctz(@bitSizeOf(Limb) * 2) == 0);
try testing.expect(limb_max.ctz(@bitSizeOf(Limb) * 2 + 1) == 0);

const limb_msb_squared: std.math.big.int.Const = .{
.limbs = &.{ 0, 1 << @bitSizeOf(Limb) - 2 },
.positive = true,
};
try testing.expect(limb_msb_squared.ctz(@bitSizeOf(Limb) * 2 - 1) == @bitSizeOf(Limb) * 2 - 2);
try testing.expect(limb_msb_squared.ctz(@bitSizeOf(Limb) * 2) == @bitSizeOf(Limb) * 2 - 2);
try testing.expect(limb_msb_squared.ctz(@bitSizeOf(Limb) * 2 + 1) == @bitSizeOf(Limb) * 2 - 2);

const limb_max_squared_minus_one: std.math.big.int.Const = .{
.limbs = &.{ 0, maxInt(Limb) - 1 },
.positive = true,
};
try testing.expect(limb_max_squared_minus_one.ctz(@bitSizeOf(Limb) * 2) == @bitSizeOf(Limb) + 1);
try testing.expect(limb_max_squared_minus_one.ctz(@bitSizeOf(Limb) * 2 + 1) == @bitSizeOf(Limb) + 1);

const limb_max_squared: std.math.big.int.Const = .{
.limbs = &.{ 1, maxInt(Limb) - 1 },
.positive = true,
};
try testing.expect(limb_max_squared.ctz(@bitSizeOf(Limb) * 2) == 0);
try testing.expect(limb_max_squared.ctz(@bitSizeOf(Limb) * 2 + 1) == 0);
}
Loading
Loading