[Tutor] I don't quite understand bitwise

Alan Gauld alan.gauld at yahoo.co.uk
Tue Dec 15 19:08:41 EST 2020


On 15/12/2020 19:11, nathan tech wrote:

> So I started to research how the x|y format works and came across 
> bitwise operators which is apparrently what is meant when x|y|z is used.

You can find a discription of nitwide operators and their use in
programming in the Functional Programming topic in my tutorial.

However long story short is:

if you do A|B

then any bit that is 1 in either A or B will be 1 in the output.

if you do A&B

then any bit that is 0 in either A or B will be 0 in the output.

Thus A|B combines the 1s in both entities - this is usually
what you want when the entities represent sets of options
such as application options and user defined options.

So if you want the total number of options set you can do

options_var = user|application
# now use the combined options_var

And A&B can be used to select a subset of options by making B
a "mask" - that is a known bit pattern.

Thus if you want to know if bits 2 and 4 of A are set to 1 do this:

B = 0b1010
res = A&B
if res == B: print("Both options are set")
else: print("One, or both, options are not set")

Finally, | can be used to accumulate results over several
operations. You used to see this before try/except
style error handling became common:

errors = 0
errors |= operation1(myObject)
errors |= operation2(myObject)
errors |= operation3(myObject)
errors |= operation4(myObject)
if errors:
   # something went wrong, deal with it!
else:
   #  All OK so now use myObject

A |= B is f course the same as
A = A|B

And if all operations return zero on success then any
other result will have some 1s in it, and these will
be transferred to errors.

For bonus points the last place you might see bitwise
operations is in cryptography.
There the exclusive OR operator is used to encode data
in such a way that it can be recovered later by applying
the same mask

#At transmitter
key = 42
data = "some string here"
cipher = ''.join(ch^key for ch in data)
print (cipher) # garbage...

# transmit cipher...

# at receiver:
key = 42   # same as transmitter
message = receiveData()
plain_text = ''.join(ch|key for ch in message)
print(plain_text)  # prints "some string here"

Of course that easy to crack but many real world cipher
systems are based on layers of algorithms on top of
a similar basic concept.

To conclude, the reason all this works is because of
the definitions of the operations as described by
their truth tables:

A	B	A|B	A&B	A^B
0	0	0	0	0
0	1	1	0	1
1	0	1	0	1
1	1	1	1	0

So
A|B is 1 when any of A or B is 1
A&B is only 1 if both  A and B are 1
A^B(exclusive or) is 1 if A and B are different.


Try them in the >>> prompt, see if you can predict the results before
hitting return:

>>> A = 0b1010
>>> B = 0b1100
>>> bin(A|B)
????
>>> bin(A&B)
????
>>> bin(A^B)
????

-- 
Alan G
Author of the Learn to Program web site
http://www.alan-g.me.uk/
http://www.amazon.com/author/alan_gauld
Follow my photo-blog on Flickr at:
http://www.flickr.com/photos/alangauldphotos




More information about the Tutor mailing list