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) {...@@ -17,12 +17,20 @@ pub fn log2(x: anytype) @TypeOf(x) {
17 },17 },
18 .Float => return @log2(x),18 .Float => return @log2(x),
19 .ComptimeInt => comptime {19 .ComptimeInt => comptime {
20 var result = 0;
21 var x_shifted = x;20 var x_shifted = x;
22 while (b: {21 // First, calculate floorPowerOfTwo(x)
23 x_shifted >>= 1;22 var shift_amt = 1;
24 break :b x_shifted != 0;23 while (x_shifted >> (shift_amt << 1) != 0) shift_amt <<= 1;
25 }) : (result += 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 }
26 return result;34 return result;
27 },35 },
28 .Int => |IntType| switch (IntType.signedness) {36 .Int => |IntType| switch (IntType.signedness) {
...@@ -36,4 +44,10 @@ pub fn log2(x: anytype) @TypeOf(x) {...@@ -36,4 +44,10 @@ pub fn log2(x: anytype) @TypeOf(x) {
36test "log2" {44test "log2" {
37 try expect(log2(@as(f32, 0.2)) == @log2(0.2));45 try expect(log2(@as(f32, 0.2)) == @log2(0.2));
38 try expect(log2(@as(f64, 0.2)) == @log2(0.2));46 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 }
39}53}