Re:EABitTricks.h
by adamnemecek on Monday December 19, 2022 @11:54AM
(#34054358)
What is the correct implementation of this?
[ Parent
| on HN ]
Re:EABitTricks.h
by psychphysic on Monday December 19, 2022 @12:29PM
(#34054802)
Have a look at popcount[0]. It's even a single instruction on many platforms [1].
This gives you the number of set bits, not the next larger number with the same number of set bits.
Re:EABitTricks.h
by psychphysic on Monday December 19, 2022 @01:54PM
(#34056038)
Filter larger, zip Popcount, filter with same popcount, min.
If you need the full implementation spelled out I can do that when I get in from my commute home.
Re:EABitTricks.h
by anonymoushn on Monday December 19, 2022 @02:08PM
(#34056219)
Step 1 is computing a set of ~2^64 things?
Re:EABitTricks.h
by psychphysic on Monday December 19, 2022 @02:38PM
(#34056590)
Lol just gotten in and looked at this at a desktop I thought we were filtering a list. My bad. Funny though.
Interesting task I guess really you want to find the first (from right) and move the first set bit left to fill it.
You could keep incrementing from the current value until the population count matches again, but in the worst case - probably from 2^62 to 2^63 with a single set bit or wrapping around from 2^63 to 2^0 - that would still take pretty much 2^64 steps.
Re:EABitTricks.h
by anonymoushn on Monday December 19, 2022 @01:10PM
(#34055405)
I think something like this would handle it
const std = @import("std");
fn snoob(x_: anytype) @TypeOf(x_) {
const T = @TypeOf(x_);
const U = comptime std.meta.Int(.unsigned, std.meta.bitCount(T));
const x = @bitCast(U, x_);
const tz = @ctz(x);
const pc = @popCount(x);
const L2U = comptime std.meta.Int(.unsigned, std.meta.bitCount(@TypeOf(tz))-1);
if (tz + pc == std.meta.bitCount(T)) {
if (pc == 0) {
return 0;
}
return @bitCast(T, (@bitCast(U, x) >> @intCast(L2U, tz)));
}
const smallest = @as(U, 1) << @intCast(L2U, tz);
const ripple = x + smallest;
const ones = ((x ^ ripple) >> 2) >> @intCast(L2U, tz);
return ripple | ones;
}
pub fn main() void { std.debug.print("Hello, {d}!", .{snoob(@as(u32,5))}); }
In addition to the stated problems with wraparound and zero (claimed fixed here) the implementation in this header file seems to have some potential correctness issue if you pass in a signed type and end up performing right shifts on values with the sign bit set and your compiler decides this means you want sign extension.
Re:EABitTricks.h
by anonymoushn on Monday December 19, 2022 @04:50PM
(#34058258)
The 2nd branch here only exists because shifting a uint32_t right by 32 is undefined. You can avoid it if you do 2 shifts instead. The first branch is tougher to get rid of.