This commit is contained in:
Miloslav Ciz 2023-01-15 14:30:11 +01:00
parent 95727ee7f0
commit 3361c59555

View file

@ -1,6 +1,16 @@
# Bit Hack
Bit hacks or bit tricks are simple clever formulas for performing useful operations with [binary](binary.md) numbers. Some operations, such as checking if a number is power of two or reversing bits in a number, can be done very efficiently with these hacks, without using loops, [branching](branchless.md) and other undesirably slow operations, potentially increasing speed and/or decreasing size and/or memory usage of code -- this can help us [optimize](optimization.md). Many of these can be found on the [web](www.md) and there are also books such as *Hacker's Delight* which document such hacks.
Bit [hacks](hacking.md) or bit tricks are simple clever formulas for performing useful operations with [binary](binary.md) numbers. Some operations, such as checking if a number is power of two or reversing bits in a number, can be done very efficiently with these hacks, without using loops, [branching](branchless.md) and other undesirably slow operations, potentially increasing speed and/or decreasing size and/or memory usage of code -- this can help us [optimize](optimization.md). Many of these can be found on the [web](www.md) and there are also books such as *Hacker's Delight* which document such hacks.
## Basics
Basic bit manipulation techniques are common and part of general knowledge so they won't be listed under hacks, but for sake of completeness and beginners reading this we should mention them here. Let's see the basic bit manipulation operators in [C](c.md):
- `|` (bitwise [OR](or.md)): Performs the logical OR on all corresponding bits of two operands, e.g. `0b0110 | 0b1100` gives 1110 (14 in decimal). This is used to set bits and combine flags (options) into a single numeric value that can easily be passed to function etc. For example to set the lowest bit of a number to 1 just do `myNumber | 1`. Now consider e.g. `#define OPTION_A 0b0001`, `#define OPTION_B 0b0010` and `#define OPTION_C 0b0100`, now we can make a single number that represents a set of selected options e.g. as `OPTION_C | OPTION_B` (the value will be `0101` and says that options B and C have been selected).
- `&` (bitwise [AND](and.md)): Performs the logical AND on all corresponding bits of two operands, e.g. `0b0110 & 0b1100` gives 0100 (4 in decimal). This may be used to mask out specific bits, to check if specific bits are set (useful to check the set flags as mentioned above) or to clear (set to zero) specific bits. Consider the flag example from above, if we want to check if value *x* has e.g. the option B set, we simply do `x & OPTION_B` which results in non-zero value if the option is set. Another example may be `myNumber & 0b00001111` (in practice you'll see hexadecimal values, i.e. `myNumber & 0x0F`) which masks out the lowest 4 bits of *myNumber* (which is equivalent to the operation [modulo](mod.md) 16).
- `~` (bitwise [NOT](not.md)): Flips every bit of the number -- pretty straightforward. This is used e.g. for clearing bits as `x & ~(1 << 3)` (clear 3rd bit of *x*).
- `^` (bitwise [XOR](xor.md)): Performs the logical XOR on all corresponding bits of two operands, e.g. `0b0110 ^ 0b1100` gives 1010 (10 in decimal). This is used to e.g. flip specific bits.
- `<<` and `>>` (bitwise shift left/right): Performs bitwise shift left or right (WATCH OUT: shifting by data type width or more is undefined behavior in C). This is typically used to perform fast multiplication (left) and division (right) by powers of two (2, 4, 8, 16, ...), just as we can quickly multiply/divide by 10 in decimal by shifting the decimal point. E.g. `5 << 3` is the same as 5 * 2^3 = 5 * 8 = 40.
## Specific Bit Hacks