为什么在乘以和除以整个整数时会失去精度?

时间:2013-09-14 13:09:43

标签: python python-3.x

我原本以为Python3应该能够处理任意长度的数字,但我遇到的问题是它们看起来并不一致。

在乘以分割之后,我的int似乎已经改变了它的内部表示,并且不再评估为它以前的自我匹配。

我正在使用整数,没有任何小数或分数,但它的行为几乎就像它正在失去舍入的精度......?

我很欣赏有关为什么会发生这种情况的任何见解,如果有什么我应该采取不同的做法。我的代码有变通方法,但由于结果是反直觉的,我很想知道行为背后的原因;)

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

如果我使用地板分割,这似乎有效 -

>>> c = b//2
>>> c
313585730727764141482831584863
>>> a == c
True

Python 2.7似乎也避免了这个场景,将它们保存在longs

>>> a = 313585730727764141482831584863
>>> a
313585730727764141482831584863L
>>> b = a*2
>>> c = b /2
>>> a
313585730727764141482831584863L
>>> c
313585730727764141482831584863L
>>> a == c
True

我很感激任何见解! 谢谢!

1 个答案:

答案 0 :(得分:11)

您正在使用真正的除法运算符/进行除法,始终将导致浮点值。改为使用楼层划分//来获取整数结果:

>>> a = 313585730727764141482831584863
>>> b = a*2
>>> c = b // 2
>>> a == c
True

您的计算机硬件无法以所需的精度处理浮点值。

另一种方法是使用decimal.Decimal() values,但这会导致算术运算速度变慢。

在Python 2中,/运算符 是分区运算符,但是当应用于整数。要在Python 2中获得相同的行为,请添加:

from __future__ import division

行为发生了变化,因为仅使用整数运算符和使用至少一个float参数之间的区别令人困惑。

换句话说,标准Python 2 /运算符是来自Python 3 /除法运算符的不同野兽。当应用于两个整数操作数时,它的行为就像Python 3中的// floor division运算符一样。但是如果两个操作数中的任何一个都是float,那么它就像/ float division运算符一样不是的。上面的__future__导入交换了Python 2 /运算符,用于Python 3中的真正除法运算符。

在反汇编Python字节码时可以看到这一点:

>>> 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        

__future__导入导致Python编译器为除法运算符使用不同的字节码,为BINARY_DIVIDE交换BINARY_TRUE_DIVIDE