I had thought Python3 is supposed to be able to handle numbers of arbitrary length, but I'm running into a problem where they don't seem to act consistently.
After multiplying then dividing, my int seems to have changed it's internal representation, and no longer evaluates as a match for it's former self.
I'm using whole numbers, without any decimals or fractions, but it's acting almost as if it's losing precision to rounding..?
I'd appreciate any insight on why this is happening, and if there's something I should be doing differently. I have workarounds for my code, but since the result is counter-intuitive, I'd love to know what's behind the behavior ;)
Python 3.3.2 (default, Jul 30 2013, 00:52:04)
[GCC 4.2.1 Compatible Apple LLVM 4.2 (clang-425.0.28)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> a = 313585730727764141482831584863
>>> a
313585730727764141482831584863
>>> b = a*2
>>> c = b /2
>>> a
313585730727764141482831584863
>>> c
3.1358573072776415e+29
>>> a == c
False
This seems to work if I use floor division, however-
>>> c = b//2
>>> c
313585730727764141482831584863
>>> a == c
True
Python 2.7 also seems to avoid this scenerio, keeping them in longs
>>> a = 313585730727764141482831584863
>>> a
313585730727764141482831584863L
>>> b = a*2
>>> c = b /2
>>> a
313585730727764141482831584863L
>>> c
313585730727764141482831584863L
>>> a == c
True
I'd appreciate any insight! Thank you!
You are dividing using the true division operator /
, which will always result in floating point values. Use floor division instead, //
, to get integer results:
>>> a = 313585730727764141482831584863
>>> b = a*2
>>> c = b // 2
>>> a == c
True
Your computer hardware cannot handle float values with the required precision.
The alternative is to use decimal.Decimal()
values, but this will result in slower arithmetic operations.
In Python 2, the /
operator is the floor division operator, but when applied to integers only. To get the same behaviour in Python 2, add:
from __future__ import division
The behaviour was changed because the difference between using only integer operators and using at least one float argument was confusing.
In other words, the standard Python 2 /
operator is a different beast from the Python 3 /
division operator. When applied to two integer operands, it acts just like the //
floor division operator in Python 3. But if either one of the two operands is a float instead, then it acts like the /
float division operator instead. The above __future__
import swaps out the Python 2 /
operator for the true division operator found in Python 3.
You can see this when disassembling Python bytecode:
>>> import dis
>>> def olddivision(x, y): return x / y
...
>>> dis.dis(olddivision)
1 0 LOAD_FAST 0 (x)
3 LOAD_FAST 1 (y)
6 BINARY_DIVIDE
7 RETURN_VALUE
>>> from __future__ import division
>>> def newdivision(x, y): return x / y
...
>>> dis.dis(newdivision)
1 0 LOAD_FAST 0 (x)
3 LOAD_FAST 1 (y)
6 BINARY_TRUE_DIVIDE
7 RETURN_VALUE
the __future__
import caused the Python compiler to use a different bytecode for the division operator, swapping BINARY_DIVIDE
for BINARY_TRUE_DIVIDE
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With