Python Forum
Thread Rating:
  • 2 Vote(s) - 2 Average
  • 1
  • 2
  • 3
  • 4
  • 5
' | ' Operator and 'OR'
#1
Hey folks. Im doing some online challanges, and I got some things that gets me confused a bit, could use some explanation!

The first one is this, I dont know what I did and why this even works?

is_divisible = lambda n,x,y : n % x | n % y == 0
I've tried to change '|' for 'or' and 'and' to see which is equivalent of '|' but its none of that, so only '|' works.

Cheers.
Reply
#2
"|" is the bitwise or operator. It compares the underlying bits of a value rather than the value itself.

Also, your conditional is incomplete. The first half will return 0 (False) when the number is divisible. It should be:

is_divisible = lambda n,x,y : n % x == 0 | n % y == 0
Reply
#3
Thx for replying!
Why its incomplete? If 'n % x' is not ==0 then returns 1 which is equal to True, otherwise its False, works for me in Python3.

Im still trying to figure out how exactly this 'binary OR' solved this, 'n % x == 0' should return value of 'True' or 'False' so its like '0001' or '0000' in binary I guess, and so the 'binary OR' copies one True to the both arguments if one is True, right? Feels like im missing something, but maybe its just that.
Reply
#4
This is why it's incomplete:

5 % 5 | 5 % 4 == 0
Output:
False
As I interpret your lambda function, you want to know if n is divisible by x or y. If you use n = 5, x = 5, and y = 4; the result is false. However, 5 is evenly divisible by 5 so the result is wrong. The interpreter is evaluating the expressions on each side of the "|" before doing the bitwise or:

5 % 5 evaluates to 0 (which is equivalent to False in Python).
5 % 4 == 0 evaluates to False (or 0).
0 | False evaluates to False.

To correct that, the first expression needs to be compared to 0 as well as the second:

is_divisible = lambda n,x,y : n % x == 0 | n % y == 0
Reply
#5
When in doubt, break it down!
>>> def divis(n, x, y):
...   print(f"n%x = {n % x}")
...   print(f"n%y = {n % y}")
...   print(f"(n%x) | (n%y) = {(n%x) | (n%y)}")
...   print(f"n % x | n % y = {n % x | n % y}")
...
>>> divis(12, 3, 5)
n%x = 0
n%y = 2
(n%x) | (n%y) = 2
n % x | n % y = 2
If a value is divisible, it'd be 0. If either value is not divisible, then the bit-or will return that non-zero number (the remainder, which happens to be 2 in this case). Using the or keyword should work the same.
Reply
#6
I'd use
not (n % x and n % y)
to know if n is divisible by x or y.
Reply
#7
I think the point is to determine if it's divisible by both, not if it's divisible by either. So it'd be not (n%x or n%y).
Reply
#8
Thank you all for replying guys. To be more precise I have to say that version with '==0' (after first expression) and without it both works the same.
is_divisible = lambda n,x,y : n % x | n % y == 0

Time: 614ms Passed: 50 Failed: 0
Test Results:
 Basic tests
Test Passed
Test Passed
Test Passed
Test Passed
Test Passed
Test Passed
Test Passed
Test Passed
Test Passed
Test Passed
 Random tests
 Testing for is_divisible(85, 7, 4)
 Testing for is_divisible(2521, 7, 18)
 Testing for is_divisible(1486, 9, 11)
 Testing for is_divisible(864, 9, 16)
 Testing for is_divisible(21, 7, 1)
 Testing for is_divisible(321, 1, 20)
 Testing for is_divisible(91, 6, 15)
 Testing for is_divisible(280, 8, 7)
 Testing for is_divisible(432, 3, 9)
 Testing for is_divisible(1361, 10, 8)
 Testing for is_divisible(2592, 9, 16)
 Testing for is_divisible(433, 9, 6)
 Testing for is_divisible(1215, 9, 9)
 Testing for is_divisible(96, 1, 8)
 Testing for is_divisible(560, 7, 20)
 Testing for is_divisible(1801, 10, 20)
 Testing for is_divisible(525, 5, 7)
 Testing for is_divisible(55, 5, 11)
 Testing for is_divisible(75, 5, 5)
Test Passed
 Testing for is_divisible(448, 8, 7)
 Testing for is_divisible(80, 8, 1)
 Testing for is_divisible(126, 9, 7)
 Testing for is_divisible(162, 9, 18)
Test Passed
 Testing for is_divisible(72, 4, 18)
 Testing for is_divisible(601, 10, 4)
 Testing for is_divisible(12, 2, 1)
 Testing for is_divisible(120, 10, 1)
 Testing for is_divisible(48, 3, 16)
 Testing for is_divisible(181, 3, 12)
 Testing for is_divisible(409, 8, 3)
 Testing for is_divisible(200, 5, 8)
 Testing for is_divisible(840, 3, 20)
 Testing for is_divisible(337, 6, 4)
Test Passed
 Testing for is_divisible(961, 4, 20)
 Testing for is_divisible(140, 7, 5)
 Testing for is_divisible(545, 2, 17)
 Testing for is_divisible(57, 4, 2)
 Testing for is_divisible(649, 9, 4)
 Testing for is_divisible(1065, 8, 19)
 Testing for is_divisible(32, 8, 4)
You have passed all of the tests! :)
Exactly the same results with '==0'.
But there is a difference between '|' and 'or':

is_divisible = lambda n,x,y : n % x ==0 or n % y == 0
#without ==0 got same results.
Time: 637ms Passed: 44 Failed: 6 Exit Code: 1
Test Results:
 Basic tests
True should equal False
Test Passed
True should equal False
Test Passed
Test Passed
True should equal False
Test Passed
Test Passed
Test Passed
Test Passed
Basic tests are very simple and looks like this, but version with 'or' wont even pass these:

Test.assert_equals(is_divisible(3,3,4),False)
Test.assert_equals(is_divisible(12,3,4),True)
Test.assert_equals(is_divisible(8,3,4),False)
Test.assert_equals(is_divisible(48,3,4),True)
Its pretty tricky to get whats going on here and on which part pythons 'or' is different from bitwise '|' for booleans.

Python 3.7.2 (tags/v3.7.2:9a3ffc0492, Dec 23 2018, 22:20:52) [MSC v.1916 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license()" for more information.
>>> import dis
>>> def div(n,x,y):
	return n % x ==0 or n % y == 0

>>> div(151,1,15)
True #Version with 'or' got the wrong answer.
>>> dis.dis('div(151,1,15)')
	
  1           0 LOAD_NAME                0 (div)
              2 LOAD_CONST               0 (151)
              4 LOAD_CONST               1 (1)
              6 LOAD_CONST               2 (15)
              8 CALL_FUNCTION            3
             10 RETURN_VALUE

>>> def div(n,x,y):
	return n % x | n % y == 0
>>> div(151,1,15)
False # Bitwise got it right.

>>> dis.dis('div(151,1,15)')
	
  1           0 LOAD_NAME                0 (div)
              2 LOAD_CONST               0 (151)
              4 LOAD_CONST               1 (1)
              6 LOAD_CONST               2 (15)
              8 CALL_FUNCTION            3
             10 RETURN_VALUE
#No differences in disassembly.
At random tests 'or' fails on every case with '1' in it. On basic ones it fails about half of it:

>>> div(8,3,4)
	
False # Bitwise is correct.
>>> def div(n,x,y):
	return n % x == 0 or n % y == 0

	
>>> div(8,3,4)
	
True # 'Or' is wrong again.
>>> 
So basically pythons 'or' does what its supposed to do and gets one that is True, but 'bitwise OR' works completely different, it retuns True only if both cases are True and I dont know why because from what I've learned it should change '0' for '1' if there is '1' in same point of any of the expressions, am I missing something? I hope at least you understand me better now!
Sorry for all the chaos.
Reply
#9
Okay, I believe I see the issue and it appears that nilamo was right. From what I'm seeing in your tests, is_divisible() should be True when n is evenly divisible by both x and y. In which case, the logic should be:

def is_divisible(n, x, y):
    return n % x == 0 and n % y == 0
Also, I noticed something odd. The bitwise statement you had was returning False for (8, 3, 4), which is the correct result according to the test you provided: Test.assert_equals(is_divisible(8,3,4),False). Going through the steps, that could only happen if the bitwise operator was evaluated prior to the equality test (==0).

Quote:8 % 3 evaluates to 2.
8 % 4 evaluates to 0.
2 | 0 evaluates to 2.
2 == 0 evaluates to False.

However, equality has higher precedence than the bitwise operator per 6.16 of the Python Language Reference. So, it should be evaluated as:

Quote:8 % 3 evaluates to 2.
8 % 4 == 0 evaluates to True.
2 | True evaluates to 3 (True).

I'm not sure what to make of that.



And I found my answer in 6.10 of the Python Language Reference:

Quote:Unlike C, all comparison operations in Python have the same priority, which is lower than that of any arithmetic, shifting or bitwise operation.
Reply
#10
(Jan-10-2019, 11:08 PM)blackknite Wrote:
is_divisible = lambda n,x,y : n % x | n % y == 0
is_divisible = lambda n,x,y : n % x ==0 or n % y == 0

Those are not the same thing. If you add the "==0" check to the bitwise operation, you'd also have failures. ie: this should fail:
is_divisible = lambda n,x,y: n%x==0 | n%y==0
Likewise, if you use or the same as you're currently using the bitwise operator, it would pass. ie: this should succeed:
is_divisible = lambda n,x,y: n%x or n%y == 0
That's because you're not actually comparing until AFTER the or is done, in both cases. They're both the same as
lambda n,x,y: (n%x | n%y) == 0
So if either value isn't evenly divisible, then or-ing the values together (using either or operator) will have a combined value of the non-zero value, which then causes the overall expression to not be equal to zero, which is False.

Doing the comparisons before or-ing the values has the opposite effect.
lambda n,x,y: (n%x==0) | (n%y==0)
This has different meaning. If either value is evenly divisible, then the overall expression is True, which gives false positives.
Reply


Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020