aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorCody Tapscott <topolarity@tapscott.me>2022-06-07 10:58:49 -0700
committerAndrew Kelley <andrew@ziglang.org>2022-06-07 20:07:40 -0400
commit70dc910086582b028d404d5de5049ceae0a95161 (patch)
tree2d7f608a2a8021e3754695353e188222d040a553 /lib
parent6ff7b437ff34e9a416a041c0c0ff8a65bae8daf5 (diff)
downloadzig-70dc910086582b028d404d5de5049ceae0a95161.tar.gz
zig-70dc910086582b028d404d5de5049ceae0a95161.zip
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.
Diffstat (limited to 'lib')
-rw-r--r--lib/std/math/log2.zig24
1 files changed, 19 insertions, 5 deletions
diff --git a/lib/std/math/log2.zig b/lib/std/math/log2.zig
index c83b170208..4158b290f0 100644
--- a/lib/std/math/log2.zig
+++ b/lib/std/math/log2.zig
@@ -17,12 +17,20 @@ pub fn log2(x: anytype) @TypeOf(x) {
},
.Float => return @log2(x),
.ComptimeInt => comptime {
- var result = 0;
var x_shifted = x;
- while (b: {
- x_shifted >>= 1;
- break :b x_shifted != 0;
- }) : (result += 1) {}
+ // First, calculate floorPowerOfTwo(x)
+ var shift_amt = 1;
+ while (x_shifted >> (shift_amt << 1) != 0) shift_amt <<= 1;
+
+ // Answer is in the range [shift_amt, 2 * shift_amt - 1]
+ // We can find it in O(log(N)) using binary search.
+ var result = 0;
+ while (shift_amt != 0) : (shift_amt >>= 1) {
+ if (x_shifted >> shift_amt != 0) {
+ x_shifted >>= shift_amt;
+ result += shift_amt;
+ }
+ }
return result;
},
.Int => |IntType| switch (IntType.signedness) {
@@ -36,4 +44,10 @@ pub fn log2(x: anytype) @TypeOf(x) {
test "log2" {
try expect(log2(@as(f32, 0.2)) == @log2(0.2));
try expect(log2(@as(f64, 0.2)) == @log2(0.2));
+ comptime {
+ try expect(log2(1) == 0);
+ try expect(log2(15) == 3);
+ try expect(log2(16) == 4);
+ try expect(log2(1 << 4073) == 4073);
+ }
}