python - 为什么通过除法而不是乘法来精确表示二进制?
问题描述
该问题的部分内容已在其他地方得到解决(例如浮点数学是否损坏?)。
以下揭示了除法与乘法生成数字的方式的差异:
>>> 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,双浮点精度。
但我不明白关于输出的三件事:
- 由于这里唯一可以用二进制精确表示的数字是 0.0 和 0.5,为什么上面打印的不是这些唯一的精确数字?
- 为什么这两个列表推导式的评估不同?
- 为什么数字的两个字符串表示不同,但它们的二进制表示不同?
>>> 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
解决方案
这里的关键点是10
用二进制精确表示,而0.1
不是。除以 10 可以获得每个分数的最接近的可能表示;乘以 0.1 的不精确转换并不能保证精度。有时你得到“足够接近”以将结果四舍五入到一个小数位,有时不是。
有足够的理由吗?
推荐阅读
- python - 输入类型不支持 ufunc 'bitwise_or'
- azure - 在创建新操作“IndexBatch.New(actions)”时,一个请求中允许多少个文档 Azure 搜索?
- flutter - 使用 Provider 和模型类搜索/过滤 ListView
- linux - 为什么 Post Build 操作不会覆盖 Jenkins 中的构建状态?
- sql-server - SQL 简单舍入
- javascript - Nodemailer:没有定义收件人,如何解决?
- spring - Spring Boot Html to Image(Html 渲染)
- android - 在 Android 上模糊图像中的区域(在 Java 中)
- c# - 使用 AWS 开发工具包从 Amazon S3 下载对象 - 结果文件已损坏
- virtual-machine - 如何将文件从本地 win 10 操作系统移动到 VMware ESXi 上的虚拟机?