Python 为什么用除法而不是乘法来表示精确的二进制数?
该问题的部分内容已在其他地方(例如)讨论过 下面揭示了通过除法和乘法生成数字的方式的不同:Python 为什么用除法而不是乘法来表示精确的二进制数?,python,computer-science,Python,Computer Science,该问题的部分内容已在其他地方(例如)讨论过 下面揭示了通过除法和乘法生成数字的方式的不同: >>> listd = [i/10 for i in range(6)] >>> listm = [i*0.1 for i in range(6)] >>> print(listd) [0.0, 0.1, 0.2, 0.3, 0.4, 0.5] >>> print(listm) [0.0, 0.1, 0.2, 0.3000000000
>>> listd = [i/10 for i in range(6)]
>>> listm = [i*0.1 for i in range(6)]
>>> print(listd)
[0.0, 0.1, 0.2, 0.3, 0.4, 0.5]
>>> print(listm)
[0.0, 0.1, 0.2, 0.30000000000000004, 0.4, 0.5]
在第二种情况下,0.3的舍入误差约为1e-16,即双浮点精度
但我不了解输出的三个方面:
这里的关键点是,
10
完全用二进制表示,而0.1
则不是。除以10得到每个分数最接近的可能表示形式;乘以0.1的不精确转换不能保证精度。有时你会“接近”到将结果四舍五入到小数点后一位,有时则不然
这就足够了吗?这里的关键点是
10
是用二进制表示的,而0.1
不是。除以10得到每个分数最接近的可能表示形式;乘以0.1的不精确转换不能保证精度。有时你会“接近”到将结果四舍五入到小数点后一位,有时则不然
这就足够了吗?回答每个问题:
如您所述,
0.1
已经不准确,因此乘以它并不完全等同于除以10
(其中至少两个输入都是精确整数)。有时,这种不准确意味着结果与除以10
不同;毕竟,你乘以的是“刚刚超过十分之一”,而不是“十分之一”。回答每个问题:
如您所述,
0.1
已经不准确,因此乘以它并不完全等同于除以10
(其中至少两个输入都是精确整数)。有时,这种不准确意味着结果与除以10
不同;毕竟,乘以“刚好超过十分之一”,而不是“十分之一”。打印浮点数的典型规则是打印出足够的小数位数,这样,如果用户实际键入打印出的内容,他们就可以得到打印出的准确值。0.4不是一个精确的二进制值,但是4/10生成的结果给出了与0.4相同的浮点数,所以这就是需要打印的全部内容。“将结果四舍五入到一个小数位”…这是Python shell自动执行的吗?@mbdeaton:不是shell,但是float
s的repr
可以为您实现这一点。它只能在不影响再现性的情况下尽可能多地循环;键入0.100000000000000555
与键入0.1
获得相同的值,因此它将表示为0.1
。相比之下,0.3
相当于0.29999999999889
,而不是0.300000000000000004
,因此,0.300000000004
不能缩短为0.3
。打印浮点数的典型规则是打印足够的小数位,这样,如果用户实际键入打印出的内容,他们就可以得到打印的准确值。0.4不是一个精确的二进制值,但是4/10生成的结果给出了与0.4相同的浮点数,所以这就是需要打印的全部内容。“将结果四舍五入到一个小数位”…这是Python shell自动执行的吗?@mbdeaton:不是shell,但是float
s的repr
可以为您实现这一点。它只能在不影响再现性的情况下尽可能多地循环;键入0.100000000000000555
与键入0.1
获得相同的值,因此它将表示为0.1
。相比之下,0.3
相当于0.299999999889
,而不是0.300000000000000004
,因此0.300000000000000004
不能缩短为0.3
。
>>> def bf(x):
return bin(struct.unpack('@i',struct.pack('!f',float(x)))[0])
>>> x1 = 3/10
>>> x2 = 3*0.1
>>> print(repr(x1).ljust(20), "=", bf(x1))
>>> print(repr(x2).ljust(20), "=", bf(x2))
0.3 = -0b1100101011001100110011011000010
0.30000000000000004 = -0b1100101011001100110011011000010