Boolean operators vs Bitwise operators - python

I am confused as to when I should use Boolean vs bitwise operators
and vs &
or vs |
Could someone enlighten me as to when do i use each and when will using one over the other affect my results?

Here are a couple of guidelines:
Boolean operators are usually used on boolean values but bitwise operators are usually used on integer values.
Boolean operators are short-circuiting but bitwise operators are not short-circuiting.
The short-circuiting behaviour is useful in expressions like this:
if x is not None and x.foo == 42:
# ...
This would not work correctly with the bitwise & operator because both sides would always be evaluated, giving AttributeError: 'NoneType' object has no attribute 'foo'. When you use the boolean andoperator the second expression is not evaluated when the first is False. Similarly or does not evaluate the second argument if the first is True.

Here's a further difference, which had me puzzled for a while just now: because & (and other bitwise operators) have a higher precedence than and (and other boolean operators) the following expressions evaluate to different values:
0 < 1 & 0 < 2
versus
0 < 1 and 0 < 2
To wit, the first yields False as it is equivalent to 0 < (1 & 0) < 2, hence 0 < 0 < 2, hence 0 < 0 and 0 < 2.

In theory, and and or come straight from boolean logic (and therefore operate on two booleans to produce a boolean), while & and | apply the boolean and/or to the individual bits of integers. There are a lot lot of questions here on how the latter work exactly.
Here are practical differences that potentially affect your results:
and and or short-circuiting, e.g. True or sys.exit(1) will not exit, because for a certain value of the first operand (True or ..., False and ...), the second one wouldn't change the result so does not need to be evaluated. But | and & don't short-circuit - True | sys.exit(1) throws you outta the REPL.
& and | are regular operators and can be overloaded, while and and or are forged into the language (although the special method for coercion to boolean may have side effects).
This also applies to some other languages with operator overloading
and and or return the value of an operand instead of True or False. This doesn't change the meaning of boolean expressions in conditions - 1 or True is 1, but 1 is true, too. But it was once used to emulate a conditional operator (cond ? true_val : false_val in C syntax, true_val if cond else false_val in Python). For & and |, the result type depends on how the operands overload the respective special methods (True & False is False, 99 & 7 is 3, for sets it's unions/intersection...).
This also applies to some other languages like Ruby, Perl and Javascript
But even when e.g. a_boolean & another_boolean would work identically, the right solution is using and - simply because and and or are associated with boolean expression and condition while & and | stand for bit twiddling.

If you are trying to do element-wise boolean operations in numpy, the answer is somewhat different. You can use & and | for element-wise boolean operations, but and and or will return value error.
To be on the safe side, you can use the numpy logic functions.
np.array([True, False, True]) | np.array([True, False, False])
# array([ True, False, True], dtype=bool)
np.array([True, False, True]) or np.array([True, False, False])
# ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
np.logical_or(np.array([True, False, True]), np.array([True, False, False]))
# array([ True, False, True], dtype=bool)

The hint is in the name:
Boolean operators are for performing logical operations (truth testing common in programming and formal logic)
Bitwise operators are for "bit-twiddling" (low level manipulation of bits in byte and numeric data types)
While it is possible and indeed sometimes desirable (typically for efficiency reasons) to perform logical operations with bitwise operators, you should generally avoid them for such purposes to prevent subtle bugs and unwanted side effects.
If you need to manipulate bits, then the bitwise operators are purpose built. The fun book: Hackers Delight contains some cool and genuinely useful examples of what can be achieved with bit-twiddling.

The general rule is to use the appropriate operator for the existing operands. Use boolean (logical) operators with boolean operands, and bitwise operators with (wider) integral operands (note: False is equivalent to 0, and True to 1). The only "tricky" scenario is applying boolean operators to non boolean operands. Let's take a simple example, as described in [SO]: Python - Differences between 'and' and '&': 5 & 7 vs. 5 and 7.
For the bitwise and (&), things are pretty straightforward:
5 = 0b101
7 = 0b111
-----------------
5 & 7 = 0b101 = 5
For the logical and, here's what [Python.Docs]: Boolean operations states (emphasis is mine):
(Note that neither and nor or restrict the value and type they return to False and True, but rather return the last evaluated argument.
Example:
>>> 5 and 7
7
>>> 7 and 5
5
Of course, the same applies for | vs. or.

Boolean operation are logical operations.
Bitwise operations are operations on binary bits.
Bitwise operations:
>>> k = 1
>>> z = 3
>>> k & z
1
>>> k | z
3
The operations:
AND &: 1 if both bits are 1, otherwise 0
OR |: 1 if either bit is 1, otherwise 0
XOR ^: 1 if the bits are different, 0 if they're the same
NOT ~': Flip each bit
Some of the uses of bitwise operations:
Setting and Clearing Bits
Boolean operations:
>>> k = True
>>> z = False
>>> k & z # and
False
>>> k | z # or
True
>>>

Boolean 'and' vs. Bitwise '&':
Pseudo-code/Python helped me understand the difference between these:
def boolAnd(A, B):
# boolean 'and' returns either A or B
if A == False:
return A
else:
return B
def bitwiseAnd(A , B):
# binary representation (e.g. 9 is '1001', 1 is '0001', etc.)
binA = binary(A)
binB = binary(B)
# perform boolean 'and' on each pair of binaries in (A, B)
# then return the result:
# equivalent to: return ''.join([x*y for (x,y) in zip(binA, binB)])
# assuming binA and binB are the same length
result = []
for i in range(len(binA)):
compar = boolAnd(binA[i], binB[i])
result.append(compar)
# we want to return a string of 1s and 0s, not a list
return ''.join(result)

Logical Operations
are usually used for conditional statements. For example:
if a==2 and b>10:
# Do something ...
It means if both conditions (a==2 and b>10) are true at the same time then the conditional statement body can be executed.
Bitwise Operations
are used for data manipulation and extraction. For example, if you want to extract the four LSB (Least Significant Bits) of an integer, you can do this:
p & 0xF

Related

Why only first or second operand gets printed? [duplicate]

I've been tinkering a little with Python operators and came across something I'm not sure about.
If I perform a bitwise operation (&, |) on 2 integers I will get unsurprisingly their bitwise value.
Meaning:
>>> a = 11
>>> b = 3
>>> a & b
3
This is because it performs bitwise AND on the binary representation of these numbers.
However, if I use the built in and operator I will get the second variable, irrespective of its type:
>>> b and a
11
>>> 'b' and 'a'
'a'
Why is it so?
Logical operators operate on the truthiness of an object. Every object has truth value, unless it has a __bool__ method that is explicitly overridden to raise an error. The major difference between a and b (logical) and a & b (bitwise) is that the former apply to any objects, while the latter only apply to numeric types that support bitwise operations1.
Python's logical operators are specifically designed to return the result of the last object evaluated:
a and b: Returns a Falsy a, or b (if a is truthy)
a or b: Returns a Truthy a, or b (if a if falsy)
From the tutorial:
The Boolean operators and and or are so-called short-circuit operators: their arguments are evaluated from left to right, and evaluation stops as soon as the outcome is determined. For example, if A and C are true but B is false, A and B and C does not evaluate the expression C. When used as a general value and not as a Boolean, the return value of a short-circuit operator is the last evaluated argument.
This property is used semi-idiomatically to check values before accessing them. For example, if a list must contain an element, you can do something like
if x and x[0] == value:
# ...
This will not raise an error, because if x is Falsy (empty), the and expression will return x instead of x[0] == value.
1 Set-like objects also support & as the intersection operator. This is conceptually similar to what the bitwise operator does for integers (you can think of bits as sets), and in no way detracts from the rest of the answer.
The documentation says:
The expression x and y first evaluates x; if x is false, its value is returned; otherwise, y is evaluated and the resulting value is returned.
Since Python considers the boolean value for both strings and non-zero integers to be True, x and y would imply True and True, and since the boolean of the first statement is not False, the second statement is evaluated and the resulting value (which is the value of the second term) is returned.
The first case with and:
>>> b and a #(11 and 3, both the values evaluates to be true because non-zero)
11
>>> 'b' and 'a' #(again both are evaluated to be true because non-empty)
For and all the conditions need to be True, so checked upto the last item if the previous evaluates to be True, hence you get the last item.
Case 1 : A and B
here consider A ,B both are non zeroes for and it checks both A,B that is it first evaluates A if in A after conversion in binary(for understanding consider positive integers , A > 0 and B > 0) whether 1 is present or not , if yes it moves to B and returns B as output. Because and checks both A and B.
A or B
here it checks the A as same as above if it has 1 after converting in to binary,
if A is True it return A (obviously A > 0 so it return A only ).
case 2 : suppose Any 1 in A,B or both A,B are ZEROES
I will try to explain in better way . I hope we all know truth tables for 'AND' and 'OR' and 'XOR'.
Same thing happening here just replace 1's and 0's with any number, if you want you use only 1's and 0's to understand in better way.

Python - why '&' and 'and' operators provide different results though evaluate the condition with same result

I have just started learning Python. I have come across the below problem. As shown below, I am writing a same statement once using '&' operator and then using 'and' operator. Though both of these operators evaluate the 'if' condition to the same Boolean output,'True' (True 'and' True is True and also True & True is True), why are the results different? Why is '&' giving wrong answer? Appreciate any clarifications.
a = 70
b = 40
c = 60
x = a if a>b and a>c else b if b>c else c
print('Max value with "and":', x)
x = a if a>b & a>c else b if b>c else c
print('Max value with "ampersand":', x)
The output is:
Max value with "and": 70
Max value with "ampersand": 60
why are the results different? Why is '&' giving wrong answer?
Because they're completely different operators with completely different semantics and completely different precedence: & applies before > which applies before and.
So when you write a > b and a > c it's parsed as (a > b) and (a > c).
But when you write a > b & a > c, it's parsed as a > (b & a) > c.
There's an other difference which is not relevant here but would be a factor in other context: and (and or) are lazy operators, meaning they will evaluate their left operands, then do their thing, and only then evaluate the second operand. & however is a normal "eager" operator, it evaluates both operands and only then applies whatever it does.
Finally, and this is of course the biggest difference: and works on everything and is non-overridable; & only works on types which specifically support it, and does whatever it was defined as (for integers it's a bitwise AND, but for sets it's intersection).

Python comparison operator precedence

All comparison operations in Python have the same priority, which is lower than that of any arithmetic, shifting or bitwise operation. Thus "==" and "<" have the same priority, why would the first expression in the following evaluate to True, different from the 2nd expression?
>>> -1 < 0 == False
True
>>> (-1 < 0) == False
False
I would expect both be evaluated to False. Why is it not the case?
Python has a really nice feature - chained comparison, like in math expressions, so
-1 < 0 == False
is actually a syntactic sugar for
-1 < 0 and 0 == False
under the hood.

Python Operators: Math Precedence Comparison operators vs equality operators

print 1>0 == (-1)<0 # => False
print (1>0) == ((-1)<0) # => True
First line prints False.
Second line prints True
The problem is if according to the order comparison operators are above equality operators.
Shouldn't both lines print True? (Or at least the same thing..)
https://www.codecademy.com/en/forum_questions/512cd091ffeb9e603b005713
Both equality and the greater than and less than operators have the same precedence in Python. But you're seeing something odd because of how an expression with multiple comparison operators in a row gets evaluated. Rather than comparing the results of previous calculations using its rules of precedence, Python chains them together with and (repeating the middle subexpressions).
The expression 1 > 0 == -1 < 0 is equivalent to (1 > 0) and (0 == -1) and (-1 < 0) (except that each of the repeated subexpressions, like -1 only gets evaluated once, which might matter if it was a function call with side effects rather than an integer literal). Since the middle subexpression is False, the whole thing is False.
In the second version, the parentheses prevent the comparison chaining from happening, so it just evaluates the inequalities independently and then compares True == True which is True.

Bit operations and the == vs != operator

I'm doing some Leetcode problems and I came across a weird problem:
for i in range(32):
if(n&mask == 1):
bits +=1
mask <<=1
return bits
This doesn't work. Now if instead of comparing if it is equal to one do the condition when it's different than 0, it works.
for i in range(32):
if(n&mask != 0):
bits +=1
mask <<=1
return bits
Aren't they doing the same thing in a different way? Shouldn't the answer be the same? The questions in the following (https://leetcode.com/problems/number-of-1-bits/description/)
No, they are not the same, as you discovered. As obvious as it sounds, ==1 checks if the value is 1, !=0 check if the value is different from 0. What you are probably missing is that values other than 1 and 0 are possible.
a&b returns the bitwise and of 2 integers: 1&1 == 1, but 2&2 == 2, and thus 2&2 != 0, but is not 1.
There is difference between and , or , not and & , | , !
and , or , not are logical operators and & , | , ! are bitwise operators.
x or y : if x is false then y , else x
x and y : if x is false then x , else y
not x : if x is false then true else false
Shortcut :
x and y : always gives y if both are not false
x or y : always gives x if both are not false
What is actually false ?
From python official doc :
Any object can be tested for truth value, for use in an if or while
condition or as operand of the Boolean operations below. The following
values are considered false:
None
False
zero of any numeric type, for example, 0, 0L, 0.0, 0j.
any empty sequence, for example, '', (), [].
any empty mapping, for example, {}.
instances of user-defined classes, if the class defines a nonzero() or len() method, when that method returns the integer zero or bool value False.2.5
All other values are considered true -- so objects of many types are always true.
Operations and built-in functions that have a Boolean result always return 0 or False for false and 1 or True for true, unless otherwise stated. (Important exception: the Boolean operations "or" and "and" always return one of their operands.)
Now what are bitwise operators?
Bitwise operators work on bit manipulation and addition :
| operator is not addition ( it perform addition basis on truth table)
& operator is not multiplication (it perform multiplication basis on truth table)
5 | 3 => 101 | 011 = 111 which is 7 in decimal
5 & 3 => 101 & 011 = 001 which is 1
You can check these in python terminal

Categories