authorgravatar for gwenzek@users.noreply.github.comGuillaume Wenzek <gwenzek@users.noreply.github.com> 2024-01-12 17:28:56+01:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-01-13 18:46:16-08:00
logc5d359e4cdcc6090f0ff1803adb929247027e7cb
tree637055ee759a05603fad17d3cced1c1fdb84e0d7
parentd55d1e32b65dd829cec17b5c5d65db10608d097c

fix #17142, wrong comptime log_int computation


3 files changed, 19 insertions(+), 6 deletions(-)

lib/std/math.zig+2
......@@ -672,6 +672,7 @@ test "rotl" {
672672/// - 1. Suitable for 0-based bit indices of T.
673673pub fn Log2Int(comptime T: type) type {
674674 // comptime ceil log2
675 if (T == comptime_int) return comptime_int;
675676 comptime var count = 0;
676677 comptime var s = @typeInfo(T).Int.bits - 1;
677678 inline while (s != 0) : (s >>= 1) {
......@@ -684,6 +685,7 @@ pub fn Log2Int(comptime T: type) type {
684685/// Returns an unsigned int type that can hold the number of bits in T.
685686pub fn Log2IntCeil(comptime T: type) type {
686687 // comptime ceil log2
688 if (T == comptime_int) return comptime_int;
687689 comptime var count = 0;
688690 comptime var s = @typeInfo(T).Int.bits;
689691 inline while (s != 0) : (s >>= 1) {
lib/std/math/log.zig+1-4
......@@ -24,11 +24,8 @@ pub fn log(comptime T: type, base: T, x: T) T {
2424 return @as(comptime_float, @log(@as(f64, x)) / @log(float_base));
2525 },
2626
27 // TODO: implement integer log without using float math.
28 // The present implementation is incorrect, for example
29 // `log(comptime_int, 9, 59049)` should return `5` and not `4`.
3027 .ComptimeInt => {
31 return @as(comptime_int, @floor(@log(@as(f64, x)) / @log(float_base)));
28 return @as(comptime_int, math.log_int(comptime_int, base, x));
3229 },
3330
3431 .Int => |IntType| switch (IntType.signedness) {
lib/std/math/log_int.zig+16-2
......@@ -7,10 +7,15 @@ const Log2Int = math.Log2Int;
77/// Returns the logarithm of `x` for the provided `base`, rounding down to the nearest integer.
88/// Asserts that `base > 1` and `x > 0`.
99pub fn log_int(comptime T: type, base: T, x: T) Log2Int(T) {
10 if (@typeInfo(T) != .Int or @typeInfo(T).Int.signedness != .unsigned)
11 @compileError("log_int requires an unsigned integer, found " ++ @typeName(T));
10 const valid = switch (@typeInfo(T)) {
11 .ComptimeInt => true,
12 .Int => |IntType| IntType.signedness == .unsigned,
13 else => false,
14 };
15 if (!valid) @compileError("log_int requires an unsigned integer, found " ++ @typeName(T));
1216
1317 assert(base > 1 and x > 0);
18 if (base == 2) return math.log2_int(T, x);
1419
1520 // Let's denote by [y] the integer part of y.
1621
......@@ -112,3 +117,12 @@ test "math.log_int vs math.log10" {
112117 }
113118 }
114119}
120
121test "math.log_int at comptime" {
122 const x = 59049; // 9 ** 5;
123 comptime {
124 if (math.log_int(comptime_int, 9, x) != 5) {
125 @compileError("log(9, 59049) should be 5");
126 }
127 }
128}