
Low Level Bit Hacks You Absolutely Must Know - wheresvic1
http://www.catonmat.net/blog/low-level-bit-hacks-you-absolutely-must-know/
======
throwaway2016a
I was asked #1 "Check if the integer is even or odd" in an interview once. Not
worded quite that way but that was the answer they were looking for.

12 years later not a single person I have hired could correctly answer that
question[1] and most of them (almost all) have been great productive software
developers. So "absolutely must know" is entirely dependent on the type of
software you write.

[1] I don't ask it in the interview, I ask it after they are hired and have
been with us a few weeks just for fun.

~~~
ladberg
What did they usually say? I know the bitwise trick, but I would say "x % 2 ==
0" if asked because it makes a lot more sense and will (almost) always compile
to the exact same code.

~~~
Hello71
In fact, newer gcc versions are unable to optimize (x & 1) == 0 at level -O1,
and require -O2. I assume that the code emitted at -O2 and -O3 for both
constructs is the more efficient version than the literal translation, even
though they are the same number of instructions.

~~~
vardump
Apparently not true, at least in a simple function.

[https://godbolt.org/g/hfpHz7](https://godbolt.org/g/hfpHz7)

    
    
      int isEven(int number)
      {
          return number & 1;
      }
    

gcc 7.3, -O1, -O2 and -O3 (identical codegen for all optimization levels):

    
    
      isEven(int):
        mov eax, edi
        and eax, 1
        ret

~~~
Hello71
that function checks if a number is odd, not even.

[https://godbolt.org/g/7Khcg9](https://godbolt.org/g/7Khcg9)

~~~
vardump
My bad. Didn't even check it at any point.

Anyways, you still prove my point. All those three are pretty close.

-O1 sete instruction is _very_ slightly unoptimal, but even it is just a fractional clock cycle.

------
twiceaday
The following is my go-to for bit hacks

[https://graphics.stanford.edu/~seander/bithacks.html](https://graphics.stanford.edu/~seander/bithacks.html)

~~~
deadgrey19
Yes! This and only this! The posted "bit hacks" are little more than bit level
manipulations exactly as intended. The Stanford hacks are truly excellent. My
favourite is:
[https://graphics.stanford.edu/~seander/bithacks.html#RoundUp...](https://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2Float)

~~~
saagarjha
Of course, casting that int * to a float * is undefined behavior…

~~~
ithkuil
Yep the correct way is:

union { int i; float f;} u; u.i=*i;

Now u.f contains the same bit pattern as the integer pointed to by "i" but
interpreted as a float.

Compilers know how to generate code efficiently out of this.

Iirc this is implementation defined behavior, e.g. things like endianness
alignment or padding, but it's not undefined behavior, whose evil effects can
bubble up in unexpected parts of the program that apparently don't even touch
the bad cast.

~~~
TeMPOraL
Wow, never realized the pointer cast version is undefined behaviour in C. Is
C++ equivalent via reinterpret_cast undefined behaviour too?

Back in my C++ days, I would much prefer pointer-cast to union-struct, because
the latter was subject to alignment/padding issues you mention, while for the
former, I know of no desktop architecture that could mess up a int* -> float*
cast.

I'm also doubly surprised because being able to do that stuff is what I'd
consider the selling point of C/C++ over higher-level languages.

~~~
jcranmer
Pretty much all pointer casts where you would use reinterpret_cast in C++ are
undefined behavior, in both C and C++. The underlying rule for strict aliasing
is essentially the same in both languages (you can only access an lvalue via a
pointer of its type, with possibly differing signedness, const, volatile, or
via a char pointer, or via a field of a struct that has the same initial
layout if you're in that same initial layout portion).

Yeah, C and C++ aren't the language most people think they are, and the strict
aliasing rules are the most clear manifestation of that.

~~~
tropo
Trouble is, C was that language. Lots of people came to depend on this. The
world needs a language with this ability.

The replacement is often "gcc with inline assembly" or "gcc with lots of
__attribute__ extensions such as __may_alias__" or "gcc with optimizations
disabled".

The need doesn't go away, despite the wishes of a language committee now
dominated by compiler suppliers. From day 1, long before the language was
standardized and even before the original (not ANSI) book was published, C was
being used with aliasing. It was, after all, developed to support the creation
of Unics (before that became UNIX).

------
askvictor
The first one (check if an integer is odd or even) is a hack, sure. But I
can't think of anywhere you'd use it in the real world over (n % 2), which
almost everyone will understand much quicker what you're doing.

The rest aren't hacks, they're bit manipulations, which are crucial for those
who need them, and just about useless to those who don't.

~~~
aurelian15
Strangely enough, I often find my self impulsively writing (n & 1) to check
for even/odd numbers. It just feels natural to me -- maybe because the first C
programs I wrote were for µCs, where this kind of bit-twiddling tends to be
used everywhere, and, correspondingly, people know what (n & 1) does. Sure
enough, even on microcontrollers (n % 2) has no overhead compared to (n & 1)
when optimisations are turned on.

It only ever caught my attention that writing (n & 1) is weird when some TAs
looking at my code didn't understand what I was doing during my first college
year.

~~~
khedoros1
It feels natural to me...but I also like writing emulators, so I've probably
got more experience in common with µC devs than most other software developers
do.

------
jnwatson
This stuff is now second nature to me after a couple decades hacking C, but
boy if it was hard to find information on this stuff as a teenager in the
early 90's.

It is easy to forget how much the internet, and the WWW in particular, has
changed programming.

~~~
JustSomeNobody
> It is easy to forget how much the internet, and the WWW in particular, has
> changed programming.

It really hasn't. It's just that web programming gets all the attention. Those
who write hardware controllers or do embedded use bit manipulation every day.

But, really, if web devs aren't familiar with this, why not? Do they not have
settings to toggle in their apps?

------
red_light
I'm sure many will disagree, but bitwise operators and operations should be
common knowledge for programmers. Why? Because it is linked to understanding
how data is stored and manipulated by computers. Computer scientists and
Engineers generally understand these operators, hackers and "coders" do not.
With this opinion, the title does not match the content.

~~~
ladberg
Is this not already common knowledge? It's taught pretty extensively in one of
the required lower div CS classes at my university, and it's usually in other
schools' curriculums from what I've seen.

~~~
sannee
So is calculus, yet apparently most CS students can't really integrate shit by
the time they get to graduation...

~~~
wink
Learned to integrate in High School, never used it again for years. Used in
like 1 out of 5 Math classes at the start university. Haven't needed it for a
good.. 13 years I guess?

Indistinguishable from "can't really integrate shit" without some hours of
relearning.

------
lsllc
Check out Hacker's Delight (2ed) by Henry S. Warren for more of this kind of
stuff.

~~~
JdeBP
A _lot_ more, if the Amazon preview is any guide. It covers this ground with
just the first couple of pages of chapter 2.

------
jacquesm
What is this now, junior programming lessons?

You absolutely must know these because they're dead obvious and if you're just
starting out with learning programming these are some of the first things you
will/should learn, right after how computers store data.

~~~
biggerfisch
While yes, these are pretty simple statements, most of them only being 2-3
operations, I think you might be interested to know that not every programming
curriculum even covers "how computers store data". I know a fair few
programmers who came from backgrounds that either never touch the difference
between an integer and float, or if they did, it was only to the point of
"this one stores fractions, this one doesn't".

For example, no python course for scientists is going to go on in-depth about
the difference between big and small endian - it just doesn't matter when
you're trying to make a simple graphical model, it's far too low level. Binary
operators work and are useful in JavaScript, but how many 6 week frontend
bootcamps are going to cover them?

What I'm getting to here is that I don't think you can just dismiss things
like this because your coding background covered them - there's some pretty
clear gaps in a lot of peoples' knowledge and educating them is likely only a
good thing.

~~~
ShroudedNight
> "this one stores fractions, this one doesn't"

This sounds like a fast trip to the land of direct comparisons of floating
point numbers.

Further info: [https://randomascii.wordpress.com/2012/02/25/comparing-
float...](https://randomascii.wordpress.com/2012/02/25/comparing-floating-
point-numbers-2012-edition/)

------
vvanders
Here I thought this was going to be something like finding the next power of
two[1].

Like a few other posters have mentioned, this is all basic bit manipulation
stuff that you'd see in any perf sensitive/memory constrained codebase.

[1]
[https://graphics.stanford.edu/~seander/bithacks.html#RoundUp...](https://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2)

------
partycoder
Also useful to generate subsets since possible the number of subsets of a set
of n elements is 2^n.

    
    
       for (int i = 0; i << n; i++) {
          ...
       }
    

(won't work for a large n)

Also... dividing by 2 is (n >> 1) and multiplying by 2 is (n << 1).

~~~
enthdegree
looping in order of subset size can be done easily too:
[https://en.wikipedia.org/wiki/Combinatorial_number_system#Ap...](https://en.wikipedia.org/wiki/Combinatorial_number_system#Applications)

------
bio_end_io_t
This assumes negatives are represented as two's-complement, but that's
implementation-defined. Testing whether a negative number is even by ANDing it
with 1 won't work in a system that uses one's-complement.

~~~
tomp
Which systems don't use two's complement?

~~~
hal_9e3
[https://en.wikipedia.org/wiki/UNIVAC_1100/2200_series#Archit...](https://en.wikipedia.org/wiki/UNIVAC_1100/2200_series#Architecture)

"I'm not dead yet!" [https://www.unisys.com/offerings/clearpath-
forward/clearpath...](https://www.unisys.com/offerings/clearpath-
forward/clearpath-forward-products/clearpath-os-2200-software)

[https://en.wikipedia.org/wiki/Ones%27_complement](https://en.wikipedia.org/wiki/Ones%27_complement)

~~~
jandrese
A handful of ancient legacy systems. Very few people today need to worry about
their webapp being ported over to UNIVAC.

------
glangdale
If you like this, you should check out
[https://graphics.stanford.edu/~seander/bithacks.html](https://graphics.stanford.edu/~seander/bithacks.html)
as mentioned elsewhere and also the book Hacker's Delight.

I would love to see these updated for SIMD and modern architectures (which
change the equation quite drastically for bit hacking with 1 uop
PEXT/PDEP/LZCNT/TZCNT), but that makes for a pretty huge area.

------
indescions_2018
See also: The Aggregate Magic Algorithms page

[http://aggregate.org/MAGIC/](http://aggregate.org/MAGIC/)

For example, Population Count instructions exist. But may actually be
microcoded to count one bit per cycle.

Vectorizing your tallies can yield log time speedups:

Faster Population Counts Using AVX2 Instructions

[https://arxiv.org/pdf/1611.07612.pdf](https://arxiv.org/pdf/1611.07612.pdf)

------
filereaper
I'd recommend anyone who's into bit-level hacking to have a copy of Henry
Warren's Hackers Delight [1]

Many of those nifty tricks are found in production systems today.

[1] [https://www.amazon.ca/Hackers-Delight-2nd-Henry-
Warren/dp/03...](https://www.amazon.ca/Hackers-Delight-2nd-Henry-
Warren/dp/0321842685)

------
textmode
Amateur k user.

    
    
      /k3
      bh01:{*-1#(2 _vs x)&1}
      bh02:{(|(2 _vs x))y}
      bh03:{n:|(2 _vs x);n[y]+:1;:[x<0;-8#|n;|n]}
      bh04:{n:|(2 _vs x);n[y]-:1;:[x<0;-8#|n;|n]}
      bh05:{n:|x;:[n[y]=1;n[y]-:1;n[y]+:1];|n}
      bh06:{n:-1#& x;x[n]-:1;x}
      bh07:{n:-1#& x;m:& 8;m[n]:+1;m}
      bh08:{n:(*|& x)+1;m:n _!#x;x[m]:1;x}
      bh09:{n:|x;m:*&0 = n;n:& 8;n[m]:1;|n}
      bh10:{n:|x;m:*&0 = n;n[m]:1;|n}
    
      /examples:
      bh01 -98
      bh02[-133;5] 
      bh03[120;2] / 120 set 2nd bit
      bh03[-120;6] / -120 set 6th bit
      bh04[127;4] / 127 unset 4th bit
      bh05[0 1 1 1 0 1 0 1;5]
      bh06[0 1 0 1 0 1 1 1]
      bh07[1 0 1 1 1 1 0 0]
      bh08[0 1 0 1 0 0 0 0]
      bh09[1 0 1 1 1 1 0 0]
      bh10[1 0 1 1 1 1 0 0]
    

Appreciated the help last time e.g. use of dyad # (take), indexing into list
via juxtaposition (bh02) and use of dyad ? (find).

~~~
textmode
bh01:{*|2 _vs x=1}

------
pointernil
\- A little off-tangent maybe, but are there other professions where this kind
of once important but today less important (as some claim) knowledge exists?
Is this kind of "knowledge degradation" common in other industries?

\- On a different note: how much of mem-space bloat can be attributed to this
low-level neglect? Which of course is partly caused by modern languages /
programming paradigms abstracting away this low level details for sake of
higher level abstractions (which only seldom break, right ;)

\- honorable exception: erlang bit-level pattern matching and all the power
that comes with it. Btw. did any other language/lib even try to imitate that
feature?

------
jiveturkey
i dunno. only like 2 of these are “hacks”. the rest are sooo basic. and he
doesn’t even have the classic swap 2 bytes/words (3 xors).

------
cowholio4
Surprised I didn’t see this one on the lists.

Shifting left by n bits on a signed or unsigned binary number has the effect
of multiplying it by 2^n. Shifting right by n bits on a two's complement
signed binary number has the effect of dividing it by 2^n, but it always
rounds down (towards negative infinity).

------
112233

      > if (x & (1<<n)) {
      >   n-th bit is set
    

Yeah, don't get a habit to do that. Instead:

    
    
      if ((x >> n) & 1)
    

if x is wider type that int or n, the result of (1<<n) may be UB, and in
practice the generated code will be buggy.

------
hinkley
Years ago I recall reading a SIGPLAN paper where someone was trying to create
a programming language where they represented bitwise operations and bitfields
without primitive types.

For the purposes of doing bit packing and other manipulations, they treated
the data as an array of booleans.

~~~
dooglius
Hardware languages such as Verilog work this way natively.

------
debatem1
Maybe I'm just off in my own little world but this seems a bit table stakes.
Am I out of touch?

~~~
jacquesm
No.

~~~
tonyarkles
While I am with you and the GP, other responses in this thread make it sound
like we _are_ in fact out of touch. Or grumpy old greybeards now... Kids these
days...

~~~
jacquesm
I suspect part of this is that hardly anybody that gets into programming
professionally has any experience with digital logic, whereas the two used to
go hand-in-hand.

But the level of this post is so low as to be next to useless, I clicked fully
expecting to be amazed. The title could definitely do with an upgrade.

------
lallysingh
This is the most clickbait programming article title I've ever seen.

~~~
jacquesm
Agreed. I've flagged it.

------
sethgecko
As a Python developer who recently wrote a pure Python ECDSA/bitcoin library,
these are very helpful. However performance is not always better. For example
I had this function:

    
    
        def point_mul(p, d):
            n = p
            q = None
        
            for i in range(256):
                if d & (1 << i):
                    if q is None:
                        q = n
                    else:
                        q = point_add(q, n)
        
                n = point_add(n, n)
            return q
    

but when i changed the loop to this :

    
    
        for i in reversed(format(d, 'b')):
            if i == '1':
    

I found out it performed much better.

~~~
tonyarkles
I 100% expect you're correct in your assertion, but here's the big question:
do you know why the latter is faster than the former?

------
juliangoldsmith
>y = x & (x-1)

Couldn't you also do: y = x & (~1) ? I'd think that would be slightly more
efficient.

~~~
Veedrac
No, that unsets bit #0, not the lowest set bit in x.

Aka. that brings 01101₂→01100₂ correctly, but 01100₂→01100₂ instead of
01100₂→01000₂.

~~~
juliangoldsmith
Ah, I completely misunderstood what the author was doing there.

------
hfdgiutdryg
I can't imagine any use for #6 on.

~~~
Veedrac
It's useful when you want to find the next free slot in some contiguous store.
Normally you'd use ctz, but sometimes you only want 1<<ctz. An example is
n-queens, eg.

[https://codereview.stackexchange.com/questions/75517/n-queen...](https://codereview.stackexchange.com/questions/75517/n-queens-
brute-force-bit-by-bit)

------
accnumnplus1
How often is this doing work that the compiler is going to do for you anyway?

~~~
dahfizz
I'm not sure I understand the question. The first one about detecting if x is
odd or even is usually what the compiler will optimize the more common (x%2)
== 0 to.

Other than that, these are things that you have to do yourself. You can't call
compiler.setMySeventhBit();

If you need to be able to flip and check bits, you have to do it yourself.

------
thankthunk
How are these hack? This is standard bit masking/manipulation? Every CS
student learns it and the C Programming Language has examples of it.

------
jankotek
Nice, but hard to read and compiler does it anyway.

