Counting set bits in an interesting way
robalni.org
robalni.org
Many languages have standard library functions, or hardware intrinsics, to emit these instructions: std::popcount in C++/20, _popcnt32 and _popcnt64 intrinsics for Intel/AMD, __builtin_popcount in gcc/clang, BitOperations.PopCount in C#, etc.
That said, the reduction in diversity of target platforms, at least on the server side, combined with convergence of language extensions support in compilers has made this less useful than it used to be. I mostly just used builtins and intrinsics these days.
Not in the embedded space. Here's the architectures supported by gcc. I suspect most of them do not have popcount equivalent instructions. I've used quite a few of them and the only places I expect hardware support are on Intel and ARM. Rarely does another arch have it.
int popcnt(unsigned int n) {
int p = 0;
while (n) {
p++;
n &= n-1;
}
return p;
}
But it has a branch in it, so I don't know if it's competitive with the "simple" version of just counting the ones or this version, even though the loop should run fewer iterations. Obviously the real answer is to just use the compiler intrinsics for this, but what fun is that? int popcount32(unsigned i) {
i = i - ((i >> 1) & 0x55555555);
i = (i & 0x33333333) + ((i >> 2) & 0x33333333);
i = ((i + (i >> 4)) & 0x0F0F0F0F);
return (i * 0x01010101) >> 24;
} n = 464d 111010000b
n-1 = 463d 111001111b
n&(n-1) = 448d 111000000bLet the compiler, and library writers take care of most of the work of translating your intention into good runtime performance and only intervene when they don't get the job done.
So this bit of x, if set, contributes (1<<i) - (1<<(i-1) + 1<<(i-2) + ... + 1<<0) = 1 to diff altogether.
https://en.wikipedia.org/wiki/Inclusion%E2%80%93exclusion_pr...
My favourite use of popcount is for packing sparse vectors.
"You can use popcount() to implement a sparse array of length N containing M < N members using bitmap of length N and a packed vector of M elements. A member i is present in the array if bit i is set, so M == popcount(bitmap). The index of member i in the packed vector is the popcount of the bits preceding i."
FWIW: These kind of sparse array tricks have been around forever:
https://gcc.gnu.org/ml/gcc-patches/2007-03/msg01308.html
The original idea for that patch didn't come from philip bagwell's paper, but from some code from the late 80's i saw at IBM.
Thus, i suspect this kind of thing has been around forever
LDX #$00 ; clear bit count
loop
ASL ; shift a bit
BCC skip ; did one shift out?
INX ; add one to count
skip
BNE loop ; repeat till zero
RTS byte EQU $EB
STA byte
LDA #$00
CLC
loop
ADC #$00
LSR byte
BNE loop
ADC #$00
RTSI never realized how much I hate this style of code until I started using Go. Go only allows Boolean conditions, so you have to do this:
> while (x >= 1)
Yeah, it's more code, but it's more readable too.
while (x >>= 1)
This makes gcc compile the code to one instruction less per iteration because it can use the status flags generated by the bitshift to determine whether to jump. Now the loop will only be 3 instructions long and the entire function 8 instructions. https://godbolt.org/z/fna8de367
Both styles are used but they have distinct meanings in context.
Many people consider that the most readable programs are those in which nothing is written in a longer more complex form, if it can be written in a shorter simpler form.
The implicit conversion of a value of any type to a Boolean value is not something invented by C. This was first used in LISP I (1960), then in many other programming languages.