mirror of
https://codeberg.org/ziglang/zig.git
synced 2026-03-08 01:24:49 +01:00
Merge pull request 'std.math.big.int: add log2 and log10 operations' (#31365) from hemisputnik/zig:work/13642-bigint-log2-log10 into master
Reviewed-on: https://codeberg.org/ziglang/zig/pulls/31365 Reviewed-by: Andrew Kelley <andrew@ziglang.org>
This commit is contained in:
commit
9ef1050bb3
2 changed files with 98 additions and 0 deletions
|
|
@ -63,6 +63,11 @@ pub fn calcLimbLen(scalar: anytype) usize {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Same as `calcToStringLimbsBufferLen`, without the useless base check.
|
||||||
|
pub fn calcLog10LimbsBufferLen(a_len: usize) usize {
|
||||||
|
return a_len + 2 + a_len + calcDivLimbsBufferLen(a_len, 1);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn calcToStringLimbsBufferLen(a_len: usize, base: u8) usize {
|
pub fn calcToStringLimbsBufferLen(a_len: usize, base: u8) usize {
|
||||||
if (math.isPowerOfTwo(base))
|
if (math.isPowerOfTwo(base))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -2670,6 +2675,62 @@ pub const Const = struct {
|
||||||
}
|
}
|
||||||
return @min(result, bits);
|
return @min(result, bits);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Calculate the base 2 logarithm, rounded down.
|
||||||
|
pub fn log2(a: Const) Limb {
|
||||||
|
return a.limbs.len * @bitSizeOf(Limb) - 1 - @clz(a.limbs[a.limbs.len - 1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Calculate the base 10 logarithm, rounded down.
|
||||||
|
///
|
||||||
|
/// The allocator is used to allocate a temporary buffer.
|
||||||
|
pub fn log10Alloc(a: Const, allocator: Allocator) Allocator.Error!Limb {
|
||||||
|
const limbs_buffer = try allocator.alloc(Limb, calcLog10LimbsBufferLen(a.limbs.len));
|
||||||
|
defer allocator.free(limbs_buffer);
|
||||||
|
|
||||||
|
return a.log10(limbs_buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Calculate the base 10 logarithm, rounded down.
|
||||||
|
///
|
||||||
|
/// `limbs_buffer` is used for temporary storage. The amount required is given by `calcLog10LimbsBufferLen`.
|
||||||
|
pub fn log10(a: Const, limbs_buffer: []Limb) Limb {
|
||||||
|
const max_digits_per_limb = std.math.log10(std.math.maxInt(Limb));
|
||||||
|
const limb_base = comptime calc: {
|
||||||
|
var limb_base: comptime_int = 1;
|
||||||
|
for (0..max_digits_per_limb) |_| limb_base *= 10;
|
||||||
|
break :calc limb_base;
|
||||||
|
};
|
||||||
|
const limb_base_as_bigint: Const = .{ .limbs = &.{limb_base}, .positive = true };
|
||||||
|
|
||||||
|
var q: Mutable = .{
|
||||||
|
.limbs = limbs_buffer[0 .. a.limbs.len + 2],
|
||||||
|
.positive = true,
|
||||||
|
.len = a.limbs.len,
|
||||||
|
};
|
||||||
|
@memcpy(q.limbs[0..a.limbs.len], a.limbs);
|
||||||
|
|
||||||
|
var remainder: Mutable = .{
|
||||||
|
.limbs = limbs_buffer[q.limbs.len..][0..a.limbs.len],
|
||||||
|
.positive = true,
|
||||||
|
.len = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
const division_buf = limbs_buffer[q.limbs.len + remainder.limbs.len ..];
|
||||||
|
|
||||||
|
var num_digits: Limb = 0;
|
||||||
|
while (q.len >= 2) {
|
||||||
|
q.divTrunc(&remainder, q.toConst(), limb_base_as_bigint, division_buf);
|
||||||
|
num_digits += max_digits_per_limb;
|
||||||
|
}
|
||||||
|
var remaining_limb = q.limbs[0];
|
||||||
|
while (remaining_limb != 0) {
|
||||||
|
remaining_limb /= 10;
|
||||||
|
num_digits += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return num_digits - 1;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/// An arbitrary-precision big integer along with an allocator which manages the memory.
|
/// An arbitrary-precision big integer along with an allocator which manages the memory.
|
||||||
|
|
|
||||||
|
|
@ -4072,3 +4072,40 @@ test "ctz" {
|
||||||
try testing.expectEqual(0, limb_max_squared.ctz(@bitSizeOf(Limb) * 2));
|
try testing.expectEqual(0, limb_max_squared.ctz(@bitSizeOf(Limb) * 2));
|
||||||
try testing.expectEqual(0, limb_max_squared.ctz(@bitSizeOf(Limb) * 2 + 1));
|
try testing.expectEqual(0, limb_max_squared.ctz(@bitSizeOf(Limb) * 2 + 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test "log2" {
|
||||||
|
var a = try Managed.init(testing.allocator);
|
||||||
|
defer a.deinit();
|
||||||
|
|
||||||
|
try a.setString(2, "1");
|
||||||
|
try testing.expectEqual(0, a.toConst().log2());
|
||||||
|
|
||||||
|
try a.setString(2, "1111011");
|
||||||
|
try testing.expectEqual(6, a.toConst().log2());
|
||||||
|
|
||||||
|
try a.setString(2, "10100111011101010");
|
||||||
|
try testing.expectEqual(16, a.toConst().log2());
|
||||||
|
|
||||||
|
try a.setString(16, "a22d71c87a9ce406da4f5895f9f3cc3d603192baf6c8a2b5c32649d0465bf188fe799b3618085e49d71bdaec01");
|
||||||
|
try testing.expectEqual(359, a.toConst().log2());
|
||||||
|
}
|
||||||
|
|
||||||
|
test "log10" {
|
||||||
|
var a = try Managed.init(testing.allocator);
|
||||||
|
defer a.deinit();
|
||||||
|
|
||||||
|
try a.setString(10, "1");
|
||||||
|
try testing.expectEqual(0, a.toConst().log10Alloc(testing.allocator));
|
||||||
|
|
||||||
|
try a.setString(10, "1234");
|
||||||
|
try testing.expectEqual(3, a.toConst().log10Alloc(testing.allocator));
|
||||||
|
|
||||||
|
try a.setString(10, "123456789");
|
||||||
|
try testing.expectEqual(8, a.toConst().log10Alloc(testing.allocator));
|
||||||
|
|
||||||
|
try a.setString(10, "57594534510580048222343352832931567593656037535732288627581929757527496850784");
|
||||||
|
try testing.expectEqual(76, a.toConst().log10Alloc(testing.allocator));
|
||||||
|
|
||||||
|
try a.setString(10, "504758845984192913149382719638135788792820830414213085834451043864912744833203879823150928260925344757009154551640690830148486352800955148298533547472300");
|
||||||
|
try testing.expectEqual(152, a.toConst().log10Alloc(testing.allocator));
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue