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
2 changes: 2 additions & 0 deletions lib/std/math.zig
Original file line number Diff line number Diff line change
Expand Up @@ -672,6 +672,7 @@ test "rotl" {
/// - 1. Suitable for 0-based bit indices of T.
pub fn Log2Int(comptime T: type) type {
// comptime ceil log2
if (T == comptime_int) return comptime_int;
comptime var count = 0;
comptime var s = @typeInfo(T).Int.bits - 1;
inline while (s != 0) : (s >>= 1) {
Expand All @@ -684,6 +685,7 @@ pub fn Log2Int(comptime T: type) type {
/// Returns an unsigned int type that can hold the number of bits in T.
pub fn Log2IntCeil(comptime T: type) type {
// comptime ceil log2
if (T == comptime_int) return comptime_int;
comptime var count = 0;
comptime var s = @typeInfo(T).Int.bits;
inline while (s != 0) : (s >>= 1) {
Expand Down
5 changes: 1 addition & 4 deletions lib/std/math/log.zig
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,8 @@ pub fn log(comptime T: type, base: T, x: T) T {
return @as(comptime_float, @log(@as(f64, x)) / @log(float_base));
},

// TODO: implement integer log without using float math.
// The present implementation is incorrect, for example
// `log(comptime_int, 9, 59049)` should return `5` and not `4`.
.ComptimeInt => {
return @as(comptime_int, @floor(@log(@as(f64, x)) / @log(float_base)));
return @as(comptime_int, math.log_int(comptime_int, base, x));
},

.Int => |IntType| switch (IntType.signedness) {
Expand Down
18 changes: 16 additions & 2 deletions lib/std/math/log_int.zig
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,15 @@ const Log2Int = math.Log2Int;
/// Returns the logarithm of `x` for the provided `base`, rounding down to the nearest integer.
/// Asserts that `base > 1` and `x > 0`.
pub fn log_int(comptime T: type, base: T, x: T) Log2Int(T) {
if (@typeInfo(T) != .Int or @typeInfo(T).Int.signedness != .unsigned)
@compileError("log_int requires an unsigned integer, found " ++ @typeName(T));
const valid = switch (@typeInfo(T)) {
.ComptimeInt => true,
.Int => |IntType| IntType.signedness == .unsigned,
else => false,
};
if (!valid) @compileError("log_int requires an unsigned integer, found " ++ @typeName(T));

assert(base > 1 and x > 0);
if (base == 2) return math.log2_int(T, x);

// Let's denote by [y] the integer part of y.

Expand Down Expand Up @@ -112,3 +117,12 @@ test "math.log_int vs math.log10" {
}
}
}

test "math.log_int at comptime" {
const x = 59049; // 9 ** 5;
comptime {
if (math.log_int(comptime_int, 9, x) != 5) {
@compileError("log(9, 59049) should be 5");
}
}
}