Strange if statement - python

I found this strange if-statement in somebody else’s code:
if variable & 1 == 0:
I don't understand it. It should have two ==, right?
Can somebody explain this?

The conditional is a bitwise operator comparison:
>>> 1 & 1
1
>>> 0 & 1
0
>>> a = 1
>>> a & 1 == 0
False
>>> b = 0
>>> b & 1 == 0
True
As many of the comments say, for integers this conditional is True for evens and False for odds. The prevalent way to write this is if variable % 2 == 0: or if not variable % 2:
Using timeit we can see that there isn't much difference in performance.
n & 1("== 0" and "not")
>>> timeit.Timer("bitwiseIsEven(1)", "def bitwiseIsEven(n): return n & 1 == 0").repeat(4, 10**6)
[0.2037370204925537, 0.20333600044250488, 0.2028651237487793, 0.20192503929138184]
>>> timeit.Timer("bitwiseIsEven(1)", "def bitwiseIsEven(n): return not n & 1").repeat(4, 10**6)
[0.18392395973205566, 0.18273091316223145, 0.1830739974975586, 0.18445897102355957]
n % 2("== 0" and "not")
>>> timeit.Timer("modIsEven(1)", "def modIsEven(n): return n % 2 == 0").repeat(4, 10**6)
[0.22193098068237305, 0.22170782089233398, 0.21924591064453125, 0.21947598457336426]
>>> timeit.Timer("modIsEven(1)", "def modIsEven(n): return not n % 2").repeat(4, 10**6)
[0.20426011085510254, 0.2046220302581787, 0.2040550708770752, 0.2044820785522461]
Overloaded Operators:
Both the % and & operators are overloaded.
The bitwise and operator is overloaded for set. s.intersection(t) is equivalent to s & t and returns a "new set with elements common to s and t".
>>> {1} & {1}
set([1])
This doesn't effect our conditional:
>>> def bitwiseIsEven(n):
... return n & 1 == 0
>>> bitwiseIsEven('1')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in bitwiseIsEven
TypeError: unsupported operand type(s) for &: 'str' and 'int'
>>> bitwiseIsEven({1})
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in bitwiseIsEven
TypeError: unsupported operand type(s) for &: 'set' and 'int'
The modulo operator will also throw TypeError: unsupported operand type(s) for most non-ints.
>>> def modIsEven(n):
... return n % 2 == 0
>>> modIsEven({1})
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in modIsEven
TypeError: unsupported operand type(s) for %: 'set' and 'int'
It is overloaded as a string interpolation operator for the old %-formatting. It throws TypeError: not all arguments converted during string formatting if a string is used for the comparison.
>>> modIsEven('1')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in modIsEven
TypeError: not all arguments converted during string formatting
This won't throw if the string includes a valid conversion specifier.
>>> modIsEven('%d')
False

This code just checks if the lowest bit of variable is a 0. Based on operator precedence this is:
if (variable & 1) == 0:
First AND the lowest bit with one (extract just the lowest bit), then check if it is 0.

The & is a bitwise operator. It returns an integer with 1 bit for every bit of its two operands that are both 1, and 0 in all other places. For example:
a = 10 # 0b1010
b = 6 # 0b0110
a & b # 0b0010
Now, if you have variable & 1, you're comparing variable against 0b1 which will only return 1 if that last digit in the binary representation is a 1, otherwise a 0.

Your only concern is probably the operator &. It is a bitwise and which takes the binary format of the two operands and perform "logic and" on each pair of bits.
For your example, consider the following:
variable = 2 #0b0010
if variable & 1 == 0:
print "condition satisfied" # satisfied, 0b0010 & 0b0001 = 0
variable = 5 #0b0101
if variable & 1 == 0:
print "condition satisfied" # not satisfied, 0b0101 & 0b0001 = 1
Note:
variable = 6 #0b0110
if variable & 2 == 0:
print "condition satisfied" # not satisfied, 0b0110 & 0b0010 = 2 (0b0010)

Related

How to fix TypeError: unsupported operand question

I'm writing a function in Python product_z which computes the product of
(N^z)/z * ∏ k/z+k from k=1 to N.
The code looks like this;
import numpy as np
def z_product(z,N):
terms = [k/(z+k) for k in range(1,N+1)]
total = (N^z/z)*np.prod(terms)
return total
However, I'm running the code with this input for example but I get a TypeError in return.
"Check that z_product returns the correct datatype."
assert type(z_product(2,7)) == np.float64 , "Return value should be a NumPy float."
print("Problem 2 Test 1: Success!")
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-9-d2e9161f328a> in <module>()
1 "Check that z_product returns the correct datatype."
----> 2 assert type(z_product(2,7)) == np.float64 , "Return value should be
a NumPy float."
3 print("Problem 2 Test 1: Success!")
<ipython-input-8-1cd27b06388f> in z_product(z, N)
1 def z_product(z,N):
2 terms = [k/(z+k) for k in range(1,N+1)]
----> 3 total = (N^z/z)*np.prod(terms)
4 return total
TypeError: unsupported operand type(s) for ^: 'int' and 'float'
What am I doing wrong and how do I fix this to make the code run?
I think you're trying to exponentiate using the ^ operator. This is the proper operator in some languages (like R or MATLAB), but is not proper python syntax. In Python, the ^ operator stands for XOR. Use ** instead:
def z_product(z,N):
terms = [k/(z+k) for k in range(1,N+1)]
total = (N**z/z)*np.prod(terms)
return total
>>> z_product(2,7)
0.6805555555555555
Alternatively, you can use np.power intead:
def z_product(z,N):
terms = [k/(z+k) for k in range(1,N+1)]
total = (np.power(N,z)/z)*np.prod(terms)
return total

TypeError: unsupported operand type(s) for &: 'NoneType' and 'BitVector'

here is the python code.
from BitVector import *
MX = BitVector(bitstring = '00011011')
MSB_check = BitVector(bitstring = '10000000')
def multiplication_logic(num):
num = num.shift_left(1) # left shift
MSB_num = num & MSB_check # AND num with 1000 0000 to get only MSB
if MSB_num.intValue() != 0:
num = num ^ MX #XOR with 00011011
return num
for indexOfOneInPoly2 in range (0,7):
if polynomial_2[indexOfOneInPoly2] == 1 and indexOfOneInPoly2 != 0:
for numberOfIndexTimes in range (0,indexOfOneInPoly2):
temp = multiplication_logic(polynomial_1)
print(temp)
polynomial_3 = polynomial_3 + temp
print(polynomial_3)
For the above code I get the error
Traceback (most recent call last):
File "<pyshell#126>", line 4, in <module>
temp = multiplication_logic(polynomial_1)
File "<pyshell#124>", line 3, in multiplication_logic
MSB_num = num & MSB_check
TypeError: unsupported operand type(s) for &: 'NoneType' and 'BitVector'
How can I make my function take parameter as a BitVector (since this is what i think is creating the problem
It looks like the BitVector.shift_left() method returns None, presumably because the bit vector is mutated in place.
There is no need to re-assign num in this case, just use:
def multiplication_logic(num):
num.shift_left(1)
MSB_num = num & MSB_check # AND num with 1000 0000 to get only MSB
if MSB_num != 0:
num = num ^ MX #XOR with 00011011
return num
If you are using the BitVector package you'll need to upgrade to version 3.1 or newer (current release is 3.4.4), as that release added return self to the BitVector.shift_left() and BitVector.shift_right() methods.
From the project changelog:
Version 3.1:
This version includes: [....] (3) The non-circular bit shift methods now return self so that they can be chained;

Math domain error in fermat

from math import sqrt
def fermatBook (n):
x=int(sqrt(n))
c=x**2-n
while (sqrt(c)!=int(sqrt(c))):
x=x+1
y=sqrt(c)
a=x+y
b=x-y
if a==1 or b==1:
print "The number is prime"
return a, b
error:
Traceback (most recent call last):
File "<pyshell#0>", line 1, in <module>
fermatBook (23867)
File "C:/Python27/fermatLivro.py", line 6, in fermatBook
while (sqrt(c)!=int(sqrt(c))):
ValueError: math domain error
I don't know what is going wrong with the program... Could someone help me ?
most likely your variable c is going negative:
Example
if you call:
n = 2
fermatBook(n)
it will assign the following values to the following variables:
x = int(sqrt(n)) = int(1.47...) = 1
c = x**2 - n = 1**2 - 2 = 1 - 2 = -1
This will likely happen alot on values of n whose square root is not an integer.
sqrt(n) >= int(sqrt(n)), n >= 0
Then when you call sqrt(c) it is out of the domain because it cannot handle negative values.
>>> from math import sqrt
>>> sqrt(-1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: math domain error
You should rather use something that can handle imaginary numbers, i.e. cmath
Or perform checks to assure this does not happen:
As an example...
if c < 0:
c = 0
As soon as you fix this however you are going to run into another problem:
This is an infinite loop:
while (sqrt(c)!=int(sqrt(c))):
x=x+1
you need to update c otherwise the condidtion will never change no matter how many times you increment x. You probably meant this?
while (sqrt(c)!=int(sqrt(c))):
x=x+1
c = x**2+n # <--- UPDATE c

Using logical operators in building a Pandas DataFrame

I have two snippets of pandas code which I think should be equivalent, but the second one doesn't do what I expect.
# snippet 1
data = all_data[[((np.isfinite(all_data[self.design_metric][i])
and all_data['Source'][i] == 2))
or ((np.isfinite(all_data[self.actual_metric][i])
and all_data['Source'][i] != 2))
for i in range(len(all_data))]]
# snippet 2
data = all_data[(all_data['Source'] == 2 &
np.isfinite(all_data[self.design_metric])) |
(all_data['Source'] != 2 &
np.isfinite(all_data[self.actual_metric]))]
Each section (e.g. all_data['Source'] == 2 ) does what I expect on its own but it seems that I'm doing something wrong with the logical operators as the final result is coming out with a different result to the list comprehension version.
The & operator binds more tightly than == (or any comparison operator). See the documentation. A simpler example is:
>>> 2 == 2 & 3 == 3
False
This is because it is grouped as 2 == (2 & 3) == 3, and then comparison chaining is invoked. This is what is happening in your case. You need to put parentheses around each comparison.
data = all_data[((all_data['Source'] == 2) &
np.isfinite(all_data[self.design_metric])) |
((all_data['Source'] != 2) &
np.isfinite(all_data[self.actual_metric]))]
Note the extra parentheses around the == and != comparisons.
Along with priority, there is a difference between AND and & operators, first one being boolean and the latter being binary bitwise. Also, you must be aware of boolead expressions.
See examples in the following snippet:
logical expressions
>>> 1 and 2
1
>>> '1' and '2'
'1'
>>> 0 == 1 and 2 == 0 or 0
0
bitwise operators
>>> 1 & 2
0
>>> '1' & '2'
Traceback (most recent call last):
...
TypeError: unsupported operand type(s) for &: 'str' and 'str'
>>> 0 == 1 & 2 == 0 | 0
True

TypeError: list indices must be integers, not float in heapsort

I can't find my mistake in here, if someone can help me would be great.
def heapsort (lista) :
n= len(lista)-1
k= n/2
while (k>0) :
downheap(lista,n,k)
k-=1
while (n>=0) :
(lista[1]),(lista[n])=(lista[n]),(lista[1])
n-=1
return downheap(lista, n, 1)
return lista
def downheap (lista, n, k) :
v= lista[k]
while (k<=(n/2)) :
j=k+k
if (j<n and (lista[j]) == (lista[j])) :
break
(lista[k]) = (lista[j])
k = j
lista[k] = v
Error:
>>> heapsort([4,2,3,1])
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 5, in heapsort
File "<stdin>", line 2, in downheap
TypeError: list indices must be integers, not float
In Python 3, using the / division operator always returns a float value:
>>> 2/2
1.0
>>> 3/2
1.5
Use floor division instead, the // operator:
k = n // 2
The // operator always returns an integer, flooring the result:
>>> 2//2
1
>>> 3//2
1
Perhaps you coded your functions from an example in Python 2; in Python 2 the / operator is an ambiguous operator; it'll act like the floor division operator when both operands are integers, but if either operand is a float, then suddenly it behaves differently and returns floating point division results instead. Because both operands in your code are integers, in Python 2 your code would not have thrown that exception.
Your next problem is that downheap() does not return anything, so when you use return downheap(lista, n, 1) in heapsort() you'll return None. I suspect that the return there is a mistake.
When dividing just cast to int
def heapsort (lista) :
n= len(lista)-1
k= int(n/2) // instead of k= n/2
while (k>0) :
downheap(lista,n,k)
k-=1
while (n>=0) :
(lista[1]),(lista[n])=(lista[n]),(lista[1])
n-=1
return downheap(lista, n, 1)
return lista

Categories

Resources