2020-10-01 16:55:46

As the topic suggests, I need assistance with understanding bitwise operations, i.e (Python)

1 ^ 2
>>> 3
1 | 2
>>> 3
1 & 2
>>> 0
~1
>>> -2

I know about binary numbers, I just do not understand how it all fits in with the operators. I have read numerous tutorials on the topic and it hasn't helped much.
I would appreciate any insight provided in regards to this topic

2020-10-01 17:33:30

Wrap the results in bin().  That will let you see the bits rather than the base 10 integer.

<< and >> are shifts and are generally an exception to the rule I'm about to explain.  << takes the string bin() returns and adds the specified number of 0s on the end.  >> chops off the specified rightmost digits.  These are effectively multiplication and divisions by powers of 2: x << n = x * (2**n), x >> n = x / (2**n).

The rest can be worked out by learning what they do to a single bit.  Once you know that, it does it to all bits in the arguments, assuming that any missing bits in the smaller number are 0.

You're confused because you don't know how to convert from base 10 to base 2 in your head.  I'd practice that some.  Also, you should practice going from base 2 to base 16.  Base 2 to base 16 (also known as hex) is actually easier, because unlike base 10 you can just consider the binary number 4 bits at a time and don't have to look at the others.  But I will leave you to the internet on that one, I don't particularly feel like typing a tutorial with a bunch of tables unless you really, really need me to.

My Blog
Twitter: @ajhicks1992

2020-10-01 20:40:20 (edited by Ethin 2020-10-01 20:41:06)

The << operator is a power-of-two multiplication. It is used for selecting a bit (e.g.: if you have a 32-bit number and each bit means something, and you want to select bit 5 so you can set it, you do 1 << 5, not 5). The >> operator is a power-of-two division and is used for isolating bit sequences. As Camlorn said, << is equivalent to 2**x, and >> is equivalent to x/(2**n).
The | operator sets bits unconditionally. If you do 0|(1 << 6), and you have an 8-bit integer, you get back an integer with bit six set. (As with all things in computing, bits are 0-based, so if you want to reference bit 32, you refer to bit 31, not 32.)
The & operator checks to see if a bit is set. If you have a 32-bit integer and you want to see if bit 18 is set, the expression x & (1 << 18) will tell you this. In C, you can do if (x & (1 << 18)), but in most other languages you must check to see if the result is explicitly greater than zero because you will get back an integral value. For instance, if you have a 32-bit integer with all bits set (0xffffffff in hex), (0xffffffff & (1 << 18)) yields 0x40000, or 262,144, therefore bit 18 is set.
The ^ operator is the exclusive or operator, also known as XOR. XOR will toggle bits. If you have a 64-bit integer and bit 60 is set, x ^ (1 << 60) will clear that bit, and doing that operation again will set that bit. You can make an entire integer zero by XORing it with itself, but note that XORing it with itself again will set (all) bits within that integer.
Finally, the ~ operator is the bitwise not operator. The ~ operator determines the bitwise compliment of each bit; that is: if there is a bit that is one, its compliment is zero; if a bit is zero, its compliment is one. In other words, ~x is equivalent to  the twos compliment of x minus one. Note that the bitwise not of an unsigned integer is its "mirror reflection" of the number across the half-way point of the range of the unsigned integer.

"On two occasions I have been asked [by members of Parliament!]: 'Pray, Mr. Babbage, if you put into the machine wrong figures, will the right answers come out ?' I am not able rightly to apprehend the kind of confusion of ideas that could provoke such a question."    — Charles Babbage.
My Github

2020-10-01 21:04:03

@3
Think it's important to clarify that though you are explaining how and why someone might use them, you're only explaining uses and that's not actually a description of what they do.

My Blog
Twitter: @ajhicks1992

2020-10-01 21:55:53 (edited by Ethin 2020-10-01 21:56:37)

@4, no, its not, but its typically how they're employed. Wikipedia does a much, much better job at explaining how they actually work than I can, even providing a mathematical equivalent to each operator. But that's Wikipedia for you. Lol

"On two occasions I have been asked [by members of Parliament!]: 'Pray, Mr. Babbage, if you put into the machine wrong figures, will the right answers come out ?' I am not able rightly to apprehend the kind of confusion of ideas that could provoke such a question."    — Charles Babbage.
My Github

2020-10-01 22:58:00

Yeah. I don't think it's important for us to explain that here unless Amerikranian specifically asks for it.  Just, thinking about them like that is only first-level understanding.  Not on your part, but in terms of learning them, it's not necessarily really a good way to think about it.

I think better to say that & does what and does to two boolean expressions, but to every pair of bits; | does what or does to two boolean expressions, but to every pair of bits, etc.  Unfortunately there's no real equivalent of ^ that works on booleans, but ~ does what not does to a boolean expression to every bit in the input, and ^ is roughly equivalent to (a and not b) or (b and not a) being applied to every pair of bits.

My Blog
Twitter: @ajhicks1992

2020-10-02 11:46:07

So programming languages are moving away from the logical operators and toward the English words and / or, fwict. The only loss from this (other than some disk space) is how the operators correspond to their bitwise counterparts.
Both & and && are doing the same thing, in terms of how they go from input to output. && is for booleans, and & is for sequences of bits, but both return True / 1 if and only if both operands are True / 1, False / 0 otherwise.
Same with || and |. Both return True / 1 if either operand is True / 1, only False / 0 if neither is True.
And really, True and False are just special cases of 1 and 0. They just plain were 1 and 0, back in the day.
So = is to == as & is to &&, as | is to ||, as ! is to ~, and in theory ^ and ^^ but I'm not sure if anyone lets you use ^^ for logical xor.
Basically, for every combination of inputs, there's an operator that returns True / 1. Except False and False / 0 and 0, but there is a logic gate for that in your CPU and you can just say not and (aka nand) for that, if you really need it. (I actually use x&~y quite a bit, just to turn off specific bits, but I don't think that uses nand under the hood? Well, OK, there's a proof that you can use nands to get all the other operations, so anything could be using nand under the hood, but I digress.).

I I suppose you use the logical operators when you need a boolean. You use the bitwise operators when you want a number. The key thing is understanding how numbers are sequences of booleans. If you think of an int as something like an array of bits, it makes more sense.
And like Camlorn said, the ability to work with binary / hexadecimal is essential to this. 1&2 == 0, because 1 and 2 have no bits in common. 1&3 == 1, because they only have the 1 bit in common. And 1|2 == 3, just like 1|3, because the 1 and 2 bits are there in both cases, but no others.
The thing that threw me was realizing that we have a bitwise xor, but no one ever teaches logical xor. Then I discovered that Python does not have a logical xor, but angelscript does, and xor is really useful for side-scrollers. Ah, well. What's a little extra code? That's how everything works, isn't it?

看過來!
"If you want utopia but reality gives you Lovecraft, you don't give up, you carve your utopia out of the corpses of dead gods."
MaxAngor wrote:
    George... Don't do that.

2020-10-02 16:21:46

In Python, you can just use bitwise xor because booleans convert to integers.  You'll either need a ^ b or you'll need int(a) ^ int(b), but either way it is actually there.  I don't understand your attachment however.  It feels like if you need logical xor for sidescrollers, you're coding something like it's still C.  I think I've seen xor seriously used like 5 times ever, it's always a notable experience.

Most languages don't use the English words.  It's not a trend by any means, and Python is the only one I personally know (but I think Ruby also does).  I'm just using them because I happen to know Amerikranian knows Python.

My Blog
Twitter: @ajhicks1992

2020-10-03 21:14:29

Thanks for the explanations. That made more sense and I was able to solve the problem at hand and learn something new in the process