authorgravatar for topolarity@tapscott.meCody Tapscott <topolarity@tapscott.me> 2022-06-07 10:58:49-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-06-07 20:07:40-04:00
log70dc910086582b028d404d5de5049ceae0a95161
tree2d7f608a2a8021e3754695353e188222d040a553
parent6ff7b437ff34e9a416a041c0c0ff8a65bae8daf5

std.math: Add O(log N) implementation of log2(x) for comptime_int

Since Zig provides @clz and not @ffs (find-first-set), log2 for comptime integers needs to be computed algorithmically. To avoid hitting the backward branch quota, this updates log2(x) to use a simple O(log N) algorithm.

1 files changed, 19 insertions(+), 5 deletions(-)

lib/std/math/log2.zig+19-5
......@@ -17,12 +17,20 @@ pub fn log2(x: anytype) @TypeOf(x) {
1717 },
1818 .Float => return @log2(x),
1919 .ComptimeInt => comptime {
20 var result = 0;
2120 var x_shifted = x;
22 while (b: {
23 x_shifted >>= 1;
24 break :b x_shifted != 0;
25 }) : (result += 1) {}
21 // First, calculate floorPowerOfTwo(x)
22 var shift_amt = 1;
23 while (x_shifted >> (shift_amt << 1) != 0) shift_amt <<= 1;
24
25 // Answer is in the range [shift_amt, 2 * shift_amt - 1]
26 // We can find it in O(log(N)) using binary search.
27 var result = 0;
28 while (shift_amt != 0) : (shift_amt >>= 1) {
29 if (x_shifted >> shift_amt != 0) {
30 x_shifted >>= shift_amt;
31 result += shift_amt;
32 }
33 }
2634 return result;
2735 },
2836 .Int => |IntType| switch (IntType.signedness) {
......@@ -36,4 +44,10 @@ pub fn log2(x: anytype) @TypeOf(x) {
3644test "log2" {
3745 try expect(log2(@as(f32, 0.2)) == @log2(0.2));
3846 try expect(log2(@as(f64, 0.2)) == @log2(0.2));
47 comptime {
48 try expect(log2(1) == 0);
49 try expect(log2(15) == 3);
50 try expect(log2(16) == 4);
51 try expect(log2(1 << 4073) == 4073);
52 }
3953}