ZrSiO4
ZrSiO4

Reputation: 201

Using the "not" and "&" operators to check for even number (Python)

I have looked at Stack overflow answers for questions similar to mine, but I have not found answers that could address my question (here and here) or explain in a way that makes it clear to me. In trying to understand, I experimented as below:

def Even1(num): # I understand this and use it
    if num % 2 == 0:
        return num 

def Even2(num):
  return not (num & 1)

def Even3(num):
  return not (num and 1)

 filter(Even1, range(7)) ==> [2, 4, 6]
 filter(Even2, range(7)) ==> [0, 2, 4, 6]
 filter(Even3, range(7)) ==> [0]

1: not (4 & 1) =  True
2: not (1 & 4) =  True
3: not (4 & 2) =  True
4: not (3 & 4) =  True
5: not (4 & 3) =  True
6: not (4 & 4) =  False

7: not (3 & 1) =  False
8: not (1 & 3) =  False
9: not (3 & 2) =  False
10: not (2 & 3) =  False
11: not (3 & 3) =  False

Based on #1 to #5 I thought any even number with any other number in a not (x & y) arrangement evaluates to False (changed to True by not). I thought it had something to do with the fact that bin(x) where x is even ends in 0 and when odd ends in a 1. So maybe not checks for the last bit. But #6 disproves that assumption. And also the order in which the numbers are presented has no influence.

What does expression #6 have in common with expression #11 besides that each evalutes identical/equal numbers?

And based on #7 to #11 it looks like odd numbers in not (x & y) where x and y both odd evaluate to True (changed to False by not). Would that be correct?

Lastly, Even2 and Even3: replace & with and. I understand that the first is bitwise, and the second logical, but what does that mean so that I end with the results.

Upvotes: 0

Views: 1484

Answers (2)

progmatico
progmatico

Reputation: 4964

Bitwise operators are usually used to make logic operations bit by bit between the operands, using the corresponding index (same weight) bit from left to right.

You have to consider the binary representation of the operands

Example:

>>> bin(4 & 6)
'0b100'
>>> bin(4)
'0b100'
>>> bin(6)
'0b110'
>>> bin(4 & 6)
'0b100'
>>> bin(8)
'0b1000'
>>> bin(4 & 8)
'0b0'
>>> bin(4 | 8)
'0b1100'
>>>

Usually you don't mix these operands with the logical ones, you may, but that's uncommon.

Bitwise operators are very useful when thinking in binary or hexadecimal terms, and also for compact representation of a group of flags.

Example (faked):

Printer status in a single byte, where bit 0 is 1 for online, 0 for offline. Bit 1 is 1 for paper jam, 0 paper ok. Bit 3 is 1 for printer ready. You don't care about the other 5 bits.

Suppose

status = 0b10100101

See the last three bits:0b101 means online, paper ok, ready

Set it offline (force bit 0 to 0)

status = status & 0b11111110 # same as status = status & 254

Get rid of status you don't care

my_status = status & 0b00000111 # same as my_status = status & 7

Set flags to 1, but keep the ones you don't care with original values

status = status | 0b00000111

The 0b numbers here are sometimes written with hexadecimal notation or even as decimal (in this case leaving them with a magical looking into the reading eyes, while binary and hexadecimal make explicit to the reader the bit values) numbers are known as a bit mask. It sets/unsets the wanted bits and preserves the rest, depending on mask value and bitwise operator (| to set and & to reset)

Now you see the rules for the logical operators you know are a bit different when dealing with True, False, 0 and empty/non-empty objects...

Upvotes: 0

quantik
quantik

Reputation: 816

In Python, 1 and 0's boolean equivalents are True and False, respectively. It doesn't stop there though any non-zero value in Python is considered True

When you do even & 1 you get 0 - because the right most bit of any even number is 0. When you execute return not 0 that's equivalent from a boolean standpoint to return not False i.e. return True

When you do not (0 and 1) that is equivalent to not (False and True) i.e. not False so return True

Let's go through some of your tests and see what we get:

not (4 & 1) = not 0100 & 0001 = not 0 = True
not (1 & 4) = not 0001 & 0100 = not 0 = True
not (4 & 2) = not 0100 & 0010 = not 0 = True
not (3 & 4) = not 0011 & 0100 = not 0 = True
not (4 & 3) = not 0100 & 0011 = not 0 = True
not (4 & 4) = not 1000 & 1000 = not 4 = False

not (3 & 1) = not 0011 & 0001 = not 1 = False
not (1 & 3) = not 0001 & 0011 = not 1 = False
not (2 & 3) = not 0010 & 0011 = not 2 = False
not (3 & 3) = not 0011 & 0011 = not 3 = False

Upvotes: 4

Related Questions