News for hackers. Stuff that matters.
Re:EABitTricks.h by adamnemecek on Monday December 19, 2022 @11:54AM (#34054358)
What is the correct implementation of this?
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].

[0] https://en.cppreference.com/w/cpp/numeric/popcount

[1] https://vaibhavsagar.com/blog/2019/09/08/popcount/

Re:EABitTricks.h by danbruc on Monday December 19, 2022 @12:56PM (#34055191)
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.

Re:EABitTricks.h by danbruc on Monday December 19, 2022 @02:44PM (#34056678)
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.