Python浮动到整数错误

时间:2018-01-06 14:49:51

标签: python floating-point type-conversion int

我很难理解这一点:

>>> 52920*(15303855351918+15303855298999)/2.0 == 809880023823263820
False
>>> 52920*(15303855351918+15303855298999)/2.0 == 809880023823263820.0
True
>>> (52920*(15303855351918+15303855298999)/2.0) - 809880023823263820
0.0
>>> int(52920*(15303855351918+15303855298999)/2.0)
809880023823263872
>>> int(52920/2.0)*(15303855351918+15303855298999)
809880023823263820

运行Python 3.5.3

数字809880023823263820显然可以表示为整数,因为它是a.p.的总和。包含所有整数参数的系列。第一次和第四次计算的解释是什么?

2 个答案:

答案 0 :(得分:2)

Python int对象具有无限精度(仅受内存限制)。 float个对象没有无限的精度;数字表示为指数和重要数字,后者用53 二进制分数构建数字。二进制分数不能代表每个可能的十进制数,这就是这里发生的事情。

使用二进制分数

809880023823263820无法清晰表示:

>>> float(809880023823263820)
8.098800238232639e+17
>>> format(float(809880023823263820), 'f')
'809880023823263872.000000'

该号码以最后两位数字的形式存储;它们是72,而不是20

请注意,浮点值始终存储为分数,指数确定小数点的位置;有非'整数部分'。非常大和非常小的数字都只是表示为小数点移动了指数的分数。

对于第三个表达式,Python 将数字转换为通用类型。从float中减去一个整数会导致整数首先转换为float。由于float(809880023823263820)-运算符左侧的结果具有相同的浮点值,因此结果为0.0

来自表达式参考文档的Binary arithmetic operations section

  

-(减法)运算符产生其参数的差异。数字参数首先转换为通用类型。

和单独的Arithmetic conversions section文档说明了这种转换是如何完成的:

  

当下面的算术运算符的描述使用短语“数字参数转换为公共类型”时,这意味着内置类型的运算符实现如下:

     
      
  • 如果任一参数是复数,则另一个参数转换为复数;
  •   
  • 否则,如果任一参数是浮点数,则另一个转换为浮点数;
  •   
  • 否则,两者必须是整数,不需要转换。
  •   

您可能想要探索有理数的不同的表示,fractionsdecimal模块。让您将有理数作为抽象分数处理,或者让您配置数字精度。

答案 1 :(得分:2)

浮点数的精度有限,而整数具有任意精度。这意味着你不能在Python中将每个整数表示为float!如果你检查,你可以很容易地看到这个:

>>> 809880023823263820 == 809880023823263820.0
False
>>> 809880023823263820 == int(809880023823263820.0)
False

来自Wikipedia

  

53位有效位精度给出15到17个有效十进制数字精度(2-53≈1.11×10-16)。如果具有最多15位有效数字的十进制字符串转换为IEEE 754双精度表示,然后转换回具有相同位数的十进制字符串,则最终结果应与原始字符串匹配。

但是你的整数有18位数,所以你不应该指望一个浮点数可以精确地代表那个整数。有些值可以精确表示,长度超过18位,但条件必须是“正确的”(例如2的幂):

>>> 2.0 ** 80 + 1 == 2 ** 80 + 1
False
>>> 2.0 ** 80 == 2 ** 80
True

你的最后一个例子实际上有点误导,因为52920/2.0可以完全表示为float,因为你实际上将它转换为一个整数,计算将完全用整数完成,并产生一个准确的整数结果。

在一般情况下,您可以使用Fraction来准确表示值:

>>> from fractions import Fraction
>>> Fraction(52920*(15303855351918+15303855298999), 2) == 809880023823263820
True

请注意, 2,而不是此处的/ 2.0