我知道这些是浮点除法。但为什么这两个公式表现不一样呢?
我做了更多调查,结果使我更加困惑:
>>>0.9/3
0.3
>>>1.2/3
0.39999999999999997
>>>1.5/3
0.5
这里有什么逻辑可以决定结果是打印一个小数位还是更多?
PS:我使用python3.4进行上述实验。
答案 0 :(得分:6)
因为浮点结果的确切值略有不同。
>>> '%.56f' % 0.4
'0.40000000000000002220446049250313080847263336181640625000'
>>> '%.56f' % (0.4/2)
'0.20000000000000001110223024625156540423631668090820312500'
>>> '%.56f' % 0.6
'0.59999999999999997779553950749686919152736663818359375000'
>>> '%.56f' % (0.6/3)
'0.19999999999999998334665463062265189364552497863769531250'
>>> '%.56f' % 0.2
'0.20000000000000001110223024625156540423631668090820312500'
>>> (0.2 - 0.6/3) == 2.0**-55
True
如您所见,打印为“0.2”的结果确实略微接近0.2。我在最后添加了这个位,以显示这两个数字之间差异的确切值。 (如果你很好奇,上面的表示是准确的值 - 添加任意数量的数字只会增加更多的零)。
答案 1 :(得分:5)
查看floating point numbers in python上的文档。
最具体:
有趣的是,有许多不同的十进制数共享相同的最接近的近似二进制分数。例如,数字0.1和0.10000000000000001和0.1000000000000000055511151231257827021181583404541015625都近似为3602879701896397/2 ** 55.由于所有这些十进制值共享相同的近似值,因此可以显示其中任何一个,同时仍保留不变eval(repr(x) )== x。
历史上,Python提示符和内置的repr()函数将选择具有17位有效数字的那一个,即0.10000000000000001。从Python 3.1开始,Python(在大多数系统上)现在能够选择最短的这些并且只显示0.1。
答案 2 :(得分:2)
浮点数根据IEEE 754实现为binary64
(与几乎所有编程语言一样)。
该标准为"有效数/分数"提供了52位。 (精度约为16位小数),指数为11位,符号为1位(正负):
特别是,0.4
这样的数字不能表示为
(1 + f) * 2**(exponent)
表示基数2中的某个分数和一个可以用11位(-1022到1023)表示的指数。
以十六进制显示0.4
,例如:
>>> (0.4).hex()
'0x1.999999999999ap-2'
我们看到我们的数字集中的最佳近似值是
+ 2**(-2) * (1 + 0x999999999999a/ float(2**52))
尝试在基础2中表示这一点,我们有
2**(-2) * (1 + 0.6)
但是在基数2中写的0.6 = 9/15 = 1001_2/1111_2
具有四个二进制数字的重复字符串
0.1001100011000110001...
所以永远不能使用有限数量的二进制数字来表示。
所以我们可以"解包" 0.4
>>> import struct
>>> # 'd' for double, '>' for Big-endian (left-to-right bits)
>>> float_bytes = struct.pack('>d', 0.4)
为8个字节(1个字节为8位)
>>> float_bytes
'?\xd9\x99\x99\x99\x99\x99\x9a'
或16个十六进制数字(1个十六进制数字是4位,因为2**4 == 16
)
>>> ''.join(['%2x' % (ord(digit),) for digit in float_bytes])
'3fd999999999999a'
或者他们荣耀中的所有64位
>>> float_bits = ''.join(['%08d' % (int(bin(ord(digit))[2:]),)
... for digit in float_bytes])
>>> float_bits
'0011111111011001100110011001100110011001100110011001100110011010'
从那里开始,第一位是符号位:
>>> sign = (-1)**int(float_bits[0], 2)
>>> sign
1
接下来的11位是指数(但是移动了1023,一个惯例
binary64
):
>>> exponent = int(float_bits[1:1 + 11], 2) - 1023
>>> exponent
-2
最后的52位是小数部分
>>> fraction = int(float_bits[1 + 11:1 + 11 + 52], 2)
>>> fraction
2702159776422298
>>> hex(fraction)
'0x999999999999a'
全部放在一起
>>> sign * 2**(exponent) * (1 + fraction / float(2**52))
0.4