Bitwise 'AND' operator and its evaluation in a code - python

I've came across bitwise operators, and they really seem odd to me. Just wanted to get clarifications on two questions that I don't fully understand. The first piece of code is:
x = raw_input('Enter a digit: ')
print 'x is %s' % ('Even', 'Odd')[x & 1]
The question is the following - How does it exactly evaluates to 'Even' if I enter an even digit, and how does it pick the first element in parenthesis after evaluation?
On top of the that, can you please explain this piece of code:
if a[i-1] & 1 and a[i] & 1:
do some stuff
Thank you all

Bitwise operations work on binary representations of your integer numbers.
if a[i-1] & 1 and a[i] & 1:
do some stuff
Checks if both the entries at positions i and i-1 are odd numbers. This is realized by checking if the rightmost (least significant) bit of the numbers is 1. Take 42 and 23 as an example:
>>> bin(42)
'0b101010'
>>> bin(23)
'0b10111'
>>> bin(1)
'0b1'
Now you can apply a bitwise AND with one to both numbers. This operator returns a binary number which has a 1 on those positions, where the first AND the second input number have a 1-bit (and only there). Shorter numbers are padded with leading zeros:
binary decimal
101010 = 42
& 000001 = 1
--------
000000 = 0
10111 = 23
& 00001 = 1
--------
00001 = 1
So basically this is another way of doing:
if a[i-1]%2 == 1 and a[i]%2 == 1:
do some stuff

Your code is broken, since it applies &, the bitwise AND, to x which holds a string. Here's what I got when I tried your code in Python 2.x:
Python 2.7.9 (default, Dec 10 2014, 12:24:55) [MSC v.1500 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> x=raw_input("enter a digit")
enter a digit4
>>> x
'4'
>>> x&1
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for &: 'str' and 'int'
You need to parse it as integer:
print "x is %s" % ("even", "odd")[int(x) & 1]
This works by "masking" out the right-most bit of x using & 1. This will be set if the number is odd, and clear if it's even. The resulting number (0 or 1) is used to index into the pair ("even", "odd").

Related

Is there a way to know whether something was rounded up or down in python? [duplicate]

This question already has answers here:
Round to 5 (or other number) in Python
(21 answers)
Closed 2 years ago.
I basically want to know whether the result of my equation (which is a simple one like this x / y) was rounded up or down.
The reason is that I have two simple statements after the rounding line like this:
if h % 2 != 0: h = h + 1
if h % 4 != 0: h = h + 2
and based on the direction of the rounding I would choose the + or - operator, so if the result was rounded up and h % 2 != 0 then it would be h = h + 1 and if it was rounded down then h = h - 1.
Does round() give that kind of information?
Also, is my math correct? (I want the result to be dividable by 4)
Try this to round to 4 directly :
import math
h = 53.75
rounded = math.round(h / 4) * 4
if (rounded > h):
print("Rounded up by " + str(rounded - h))
else:
print("Rounded down by " + str(h - rounded))
Using round() if the number after the given decimal is:
>=5 that + 1 will be added to the final value.
<5 that the final value will return as is to the mentioned decimals.
But you can use ceil or floor from the math package where it always rounds up or down, respectively.
import math
>>> math.ceil(5.2)
6
>>> math.floor(5.9)
5
Let's say you want to know whether 3.9 and 4.4 were rounded. You can do something like this:
def is_rounded_down(val, ndigits=None):
return round(val, ndigits) < val
Then you can simply call the function to find out
>>> is_rounded_down(3.9)
False
>>> is_rounded_down(4.4)
True
By default round() doesn't give that information, so you need to check yourself.
For Python 2.X integer division returns an integer and always rounds down.
add#LM1756:~$ python
Python 2.7.13 (default, Sep 26 2018, 18:42:22)
>>> print 8/3
2
>>> print type(5/2)
<type 'int'>
For Python 3.X integer division returns a float, and so there is no rounding.
add#LM1756:~$ python3
Python 3.5.3 (default, Sep 27 2018, 17:25:39)
>>> print(8/3)
2.6666666666666665
>>> type(8/3)
<class 'float'>
>>>

Converting from Float to Int changed the output

I defined a simple sqrt function to calculate a square root of a given number.
def sqrt(n):
low = 0
up = n
for i in range(50):
mid = float(low+up)/2
if pow(mid,2) < n:
low = mid
elif pow(mid,2) > n:
up = mid
else:
break
return mid
When I do:
print(sqrt(9))
I get 3.0 as the output. However when I do:
print(int(sqrt(9))) I get 2.
Could somebody please help me understand why this is happening?
Thank you.
Actually, sqrt(9) returns 2.9999999999999973 [1], at least in Python version 3.5 (and perhaps all versions 3.x?). And int returns only the integer component of the number. That's why you get 2 as the result, as the integer component of 2.9999999999999973 is indeed 2.
If you want to round the result to the nearest integer, you can do round(sqrt(9)) which produces 3.
[1] To understand why this happens and how to fix this issue, you can refer to this post.
It is because of rounding. Your method definition actually computes the sqrt(9) to be 2.9999999999999973. However the rounding is not applied to casting, therefore the decimal is lost in the casting of int(2.9999999999999973).
When you print directly, python applies rounding which brings this value up to 3.
Python 2.7 output:
Python 2.7.17 (v2.7.17:c2f86d86e6, Oct 19 2019, 21:01:17) [MSC v.1500 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>>
>>> def sqrt(n):
... low = 0
... up = n
... for i in range(50):
... mid = float(low+up)/2
... if pow(mid,2) < n:
... low = mid
... elif pow(mid,2) > n:
... up = mid
... else:
... break
... return mid
...
>>> sqrt(9)
2.9999999999999973
>>> print(sqrt(9))
3.0
>>> print(int(sqrt(9)))
2
>>>
If you want to get converted into int you can use the following:
print(int(round(sqrt(9))))

Python Comparing Large Numbers

How does one compare large numbers python?
I have the following two numbers:
x = 99 ^ 85, y = 73 ^ 62.
Computing both numbers in the python interpreter gives the following results:
>>> x = 99 ** 85
>>> x
42559012338865490805205255842468783301592970011660094241731171697575386634867177511754750618655432231509140219114042806178869109409115320236642740915044006252790234308499
>>> y = 73 ** 62
>>> y
33575100975948386797110696048991269305533302609246066947133332393856972076850553634350302934134549900847114729991729
Even without computing the results it's quite obvious that x will be greater than y. I performed mod 1000000007 on both numbers in order to reduce the number of digits. I got the following results:
>>> mod = 1000000007
>>> x % mod
195405172
>>> y % mod
297675700
>>>
As you can see the mod results of the numbers results in y being greater than x. Is there an efficient of comparing large numbers and get the right results. I don't think this problem is bound to python alone though the context of the question is under python.
Thanks in advance
Please see this question How does % work in Python?
Modulo give you the remainder of a number. So 4 % 10 = 4 and 14 % 10 = 4. So for directly comparing two numbers you will lose information by using modulo.
Comparing large numbers is pretty quick in python. Use ipython's %timeit to see.
%timeit (99 ** 85)>( 73 ** 62 )
On my system ( an older i7, 14 GB of ram) it took 46.3 nano seconds which is about as fast as any operation in python.
The 'size' of the number have a very small influence in term of execution :
'big numbers' :
>>> timeit.timeit('a=99**85; b=73**52; a>b')
0.07298588752746582
'small numbers':
>>> timeit.timeit('a=5**2; b=6**3; a>b')
0.07102680206298828
If the question is how to compare numbers in python use > and < :
>>> 5>9
False
>>> 5<9
True

Python: Median of a list of numbers

When I run my program on PyScripter, I get the expected median of 4.5. But running the same code on Ideone as here or on codeacademy returns 4. Any idea why the different results? Thanks.
#Create a function that returns the median of a list of numbers
def median(list_of_numbers):
#Make a copy of list_of_numbers and sort the new list
lst = list_of_numbers
lst = sorted(lst)
#Get the length of list and use it to index through the list
lst_length = len(lst)
index = int(lst_length/2)
#If length if even, average the two middle numbers
if lst_length%2==0:
a= lst[index-1]
b = lst[index]
result = (a+b)/2
#If length is odd, return the middle number
else:
result = lst[index]
return result
print (median([4, 5, 5, 4]))
My PyScripter version: * Python 3.3.5 (v3.3.5:62cf4e77f785, Mar 9 2014, 10:37:12) [MSC v.1600 32 bit (Intel)] on win32. *
For Python 2.x you will need to replace both occurrences of 2 by 2. in order to enforce floating point division.
Your link to ideone is Python 2.x and apparently so is your codeacademy interpreter.
import statistics as s
def mid(data):
return(int(s.median(data)))
middle = mid([3,4,6,3,12,6,45,32,78])
print(middle)
I'd use the statistics module. If you want your output to be an integer or a float, just cast it (float() or int() respectively).

How to convert an integer to variable length byte string?

I want to convert an integer (int or long) a big-endian byte string. The byte string has to be of variable length, so that only the minimum number of bytes are used (the total length length of the preceding data is known, so the variable length can be inferred).
My current solution is
import bitstring
bitstring.BitString(hex=hex(456)).tobytes()
Which obviously depends on the endianness of the machine and gives false results, because 0 bits are append and no prepended.
Does any one know a way to do this without making any assumption about the length or endianess of an int?
Something like this. Untested (until next edit). For Python 2.x. Assumes n > 0.
tmp = []
while n:
n, d = divmod(n, 256)
tmp.append(chr(d))
result = ''.join(tmp[::-1])
Edit: tested.
If you don't read manuals but like bitbashing, instead of the divmod caper, try this:
d = n & 0xFF; n >>= 8
Edit 2: If your numbers are relatively small, the following may be faster:
result = ''
while n:
result = chr(n & 0xFF) + result
n >>= 8
Edit 3: The second method doesn't assume that the int is already bigendian. Here's what happens in a notoriously littleendian environment:
Python 2.7 (r27:82525, Jul 4 2010, 09:01:59) [MSC v.1500 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> n = 65539
>>> result = ''
>>> while n:
... result = chr(n & 0xFF) + result
... n >>= 8
...
>>> result
'\x01\x00\x03'
>>> import sys; sys.byteorder
'little'
>>>
A solution using struct and itertools:
>>> import itertools, struct
>>> "".join(itertools.dropwhile(lambda c: not(ord(c)), struct.pack(">i", 456))) or chr(0)
'\x01\xc8'
We can drop itertools by using a simple string strip:
>>> struct.pack(">i", 456).lstrip(chr(0)) or chr(0)
'\x01\xc8'
Or even drop struct using a recursive function:
def to_bytes(n):
return ([chr(n & 255)] + to_bytes(n >> 8) if n > 0 else [])
"".join(reversed(to_bytes(456))) or chr(0)
If you're using Python 2.7 or later then you can use the bit_length method to round the length up to the next byte:
>>> i = 456
>>> bitstring.BitString(uint=i, length=(i.bit_length()+7)/8*8).bytes
'\x01\xc8'
otherwise you can just test for whole-byteness and pad with a zero nibble at the start if needed:
>>> s = bitstring.BitString(hex=hex(i))
>>> ('0x0' + s if s.len%8 else s).bytes
'\x01\xc8'
I reformulated John Machins second answer in one line for use on my server:
def bytestring(n):
return ''.join([chr((n>>(i*8))&0xFF) for i in range(n.bit_length()/8,-1,-1)])
I have found that the second method, using bit-shifting, was faster for both large and small numbers, and not just small numbers.

Categories