Search code examples
binarybit-manipulationbitwise-operatorsbit

What are bits and bitwise operations used for?


Can someone please explain, in very simple, simple terms why we need bitwise operators? I just started programming one month ago.

I understand that everything is stored in binary form. I understand computers count in base 2. And I understand the bitwise operators. I just don't understand what kind of programming would require using bits and bitwise operators?

I tried to look for the answer on the web, and I read something do with binary flags and disabilities, and got even more confused.

I guess I'm just wondering, what kind of real life application would require bits and bitwise operators?


Solution

  • You can pack data in a very concise format.

    The smallest amount that an x86 computer can adress is a byte - that's 8 bits.

    If your application has a 24 yes/no flags (bools), would you store them in 1 byte each? That's 24 bytes of data. If you use bits, then each byte contains 8 of those bools - so you only need 3 bytes for 24 yes/no values:

    > 1 Byte per flag:
    > 0000 0000 = off
    > 0000 0001 = on
    > Easy to check: if(b == 0) { /* flag is off */ } else if(b == 1) { /* flag is on */ }
    
    > 1 Bit per flag
    > 0011 1101 = Flags 1, 4, 8, 16 and 32 are on, flags 2, 64 and 128 are off
    > Packs 8 flags in 1 byte
    > Harder to check:
    > if( (b & 32) != 0) { /* Flag 32 is on */ }
    

    This is important for network protocols and other systems where every byte really counts.

    For general purpose business applications, there is usually no need for the additional complexity, just use 1 byte per flag.

    This isn't just used for bools. For example, some applications may want to store two numbers than can go from 0-15 - an example is the Commodore 64 which really needed to conserve RAM wherever possible. One byte can hold two of those numbers:

    > Instead of interpreting this as 8 bits (ranging from 1 to 128)
    > this is really two 4 bit numbers:
    > 1001 0110
    > First Number: 1001 = 1 + 8 = 9
    > Second Number: 0110 = 2 + 4 = 6
    >
    > Getting the first number requires a bit shift to move them into position:
    > (b >> 4) turns the above number into this:
    > 0000 1001 - this can now be simply cast as a byte and returns 9
    >
    > The second number requires us to "turn off" the first 4 bits
    > We use the AND operator for this: b = (b & 15)
    > 15 in decimal is 0000 1111 in binary.
    >
    > 1001 0110 AND
    > 0000 1111 =
    > 0000 0110
    >
    > Once again, the result can be interpreted as a byte and results in the number 6
    

    One more really neat trick is to quickly check if a number is even or odd. An odd number always has the lowest significant bit (the 1 Bit) set, while an even numer always as it clear.

    So your check for IsEven looks like this:

    return (b & 1) == 0; // Bit 1 not set - number is even
    

    (Note: Depending on the language, Compilers MAY decide to optimize stuff, but in a nutshell, that's it)