<< means shift left (moves the bits to the left side)
1 << 1 = 2 because (0001 << 1 = 0010 = 2)
3 << 1 = 6 because (0011 << 1 = 0110 = 6)
>> works in the same way
2 >> 1 = 1 because (0010 >> 1 = 0001)
The other operators are exactly the same you'd find in electronics (and boolean algebra):
~ is the NOT operator
& is the AND operator
^ is the XOR operator
Sorry, I don't have a visual representation for this (I haven't looked for a link) but I would strongly suggest to write it down on paper and do some small exercises (checking with the result then on your favorite programming language).
On a day to day basis, you'd likely not use these operators at all, but as soon as you start decoding protocols or working on a bit-level, those are super useful!
I would suggest trying to decode a bitstream protocol to really grasp the concepts: you'd use masks and bitwise operators a lot :)
I struggled with this as well. Now I'm a bit rusty as I haven't used it for a while, but what really helped me was to start thinking about binary numbers more as strings. It also really helps me to visualize binary operations in binary space, not hex or decimal. That's still very confusing to me.
For example left shift by 1 on this 8 bit number (decimal is 32)
00100000
you just shift all the numbers to the left
01000000
--------
There's some wrapping behavior of course. Like what happens if you left shift 3 here? If it's an unsigned 8 bit number the 1 would teleport to the right side.
00000001
--------
the logical operators work like this (read downwards)
00010000 AND
00010000 =
00010000
--------
00001000 AND
00010000 =
00000000
--------
00001000 OR
00010000 =
00011000
With this in mind, I found it to be a good exercise to implement common bitwise operators that work on fixed length strings with some tests against the real binary operators in your favorite language.
> There's some wrapping behavior of course. [...] the 1 would teleport to the right side.
Not really. Shifting by definition discards 1 bits once they pass either "edge" of the value. The wrapping you describe only happens with rotation operations. In the languages I know they don't have fancy short hand syntax like shifting does.
> It also really helps me to visualize binary operations in binary space, not hex or decimal. That's still very confusing to me.
Yeah, I think thats a major part of the problem for me. When im looking at these code snippets (as per ungolfed version of the post in a comment below) applying the operators to integers i just cant understand what it is they are trying to achieve, so I am unable to grok the purpose/intent. Even with the explanations given here im not sure why its doing what its doing - and I dont seem to encounter that issue outside of bitwise operators.
Thanks, but its still a bit confusing for me. Im looking for a really dumbed down kind of approach: input, operator, visual explanation of what its doing, output. Im a really bad learner, and didnt study computer science or anything. Ive never had a reason to touch binary, so find these operators unintuitive.
I think before you can understand binary operators, you’ll need to understand binary itself and how to convert it to and from decimal. This crash course computer science video may help: https://youtu.be/1GSjbWt0c9M
I understand the conversion and representation - i guess I just dont understand the intent behind the usage of these operators.
Without stepping through each line in a debugger I literally have no idea what the ungolfed version of the main post is doing, or why its doing it - and this seems to be typical of my experience with bitwise operators.
But I will definitely have a look at the references you have given. Hopefully that will give me a more intuitive understanding. Thanks.
There's many reasons for bitwise operators to exist.
For instance it's extremely easy, when looking at the binary representation of a number to check the correct end of the byte and determine if a number is odd or even.
You can use bitwise operators to bit shift and check if a value is over a certain amount but seeing if there is any value after a bit shift.
there's tonnes of real world applications:
* Bit fields (flags)
As they're the most efficient way of representing something whose state is defined by several "yes or no" properties. ACLs are a good example; if you have let's say 4 discrete permissions (read, write, execute, change policy), it's better to store this in 1 byte rather than waste 4. These can be mapped to enumeration types in many languages for added convenience.
* Communication over ports/sockets
Always involves checksums, parity, stop bits, flow control algorithms, and so on, which usually depend on the logic values of individual bytes as opposed to numeric values, since the medium may only be capable of transmitting one bit at a time.
* Compression, Encryption
Both of these are heavily dependent on bitwise algorithms. Look at the deflate algorithm for an example - everything is in bits, not bytes.
* Finite State Machines
I'm speaking primarily of the kind embedded in some piece of hardware, although they can be found in software too. These are combinatorial in nature - they might literally be getting "compiled" down to a bunch of logic gates, so they have to be expressed as AND, OR, NOT, etc.
* Graphics
There's hardly enough space here to get into every area where these operators are used in graphics programming. XOR (or ^) is particularly interesting here because applying the same input a second time will undo the first. Older GUIs used to rely on this for selection highlighting and other overlays, in order to eliminate the need for costly redraws. They're still useful in slow graphics protocols (i.e. remote desktop).
the wiki is a visual representation. The representation is 0s and 1s.
The use case for bitwise operations is to control the value of 1 bit.
Consider if you have a 0000 1000 value. It's mapped to hardware output so the 4th LED is on. Now you want to turn the 5th on, and the 4th off. You would use a left shift so the output becomes 0001 0000.
That's all there is to it. Bitwise operators operate on bits, not bytes. Because computers operate on bytes, and you can't address a bit - you have to modify bytes to accomplish your goal.
> Bitwise operators operate on bits, not bytes. Because computers operate on bytes, and you can't address a bit - you have to modify bytes to accomplish your goal.
I think this may be the fundamental intent I was missing. How do people wrangle these things in their head! Is it ever intuitive, or are even the proficient externally visualising this stuff in some way?
If you don't know about the binary representation, you won't be able to learn binary operators. If you do, they're fairly straightforward. I'd suggest learning about binary first.
You'll just have to use it in actual programs to really understand it. You can't properly understand `if` and `for` either just by reading some doc page about it, you can't become a guitarist just by reading about technique, you don't become a carpenter just about reading about it, etc. So don't feel bad if you're confused by just reading that page.
Reading didn't do the trick for me. It clicked when I started writing code to accomplish tasks, like assignments or coding puzzles, that required bitwise operations.
It helps if you look into bits and binary arithmetic; I learned it from the appendix of my school book Structured Computer Organization. Binary and binary arithmetic is probably the best place to start.