为什么在大多数编程语言中 0.1 + 0.2 不等于 0.3?

举报
Python新视野 发表于 2021/11/30 15:02:47 2021/11/30
【摘要】 前言在文章开始之前先看下面“诡异”的一幕。a, b = 0.1, 0.2print(a + b == 0.3)print(a + b)out:False0.300000000000000040.1 + 0.2 == 0.3 结果竟然为 False ?不知道大家第一次见到这个场景作何感想,反正我是有点怀疑人生,为什么会产生这样的结果呢,下面详细看一下。 浮点数的限制浮点数在计算机硬件中表示为...

前言

在文章开始之前先看下面“诡异”的一幕。

a, b = 0.1, 0.2
print(a + b == 0.3)
print(a + b)

out:
False
0.30000000000000004

0.1 + 0.2 == 0.3 结果竟然为 False ?不知道大家第一次见到这个场景作何感想,反正我是有点怀疑人生,为什么会产生这样的结果呢,下面详细看一下。

浮点数的限制

浮点数在计算机硬件中表示为一个以 2 为基数(二进制)的小数。我们先看看如果用十进制和二进制来表示0.125(10)。

十进制

0.125(10)

等于

1 × 1 0 1 + 2 × 1 0 2 + 5 × 1 0 3 = 1 8 1\times10^{-1} + 2\times10^{-2} + 5\times10^{-3} = \cfrac{1}{8}

二进制

0.001(2)

0 × 2 1 + 0 × 2 2 + 1 × 2 3 = 1 8 0\times2^{-1} + 0\times2^{-2} + 1\times2^{-3} = \cfrac{1}{8}

这两个小数均表示 0.125(10),唯一真正的区别是第一个是以 10 为基数的小数表示法,第二个则是 2 为基数。

不幸的是,大多数的十进制小数都不能精确地表示为二进制小数,但有些浮点数也能够用二进制精确的表述,条件是位数有限且分母能表示成 2^n 的小数。如 0.5, 0.125。这将导致在大多数情况下,你输入的十进制浮点数都只能近似地以二进制浮点数形式储存在计算机中。

正如上文中的 0.1 ,我们手动计算一下它的二进制结果。

注:十进制整数转二进制方法:除2取余;十进制小数转二进制方法:乘2除整

计算过程:

0.1 * 2 = 0.2 # 0
0.2 * 2 = 0.4 # 0
0.4 * 2 = 0.8 # 0
0.8 * 2 = 1.6 # 1
0.6 * 2 = 1.2 # 1
0.2 * 2 = 0.4 # 0
0.4 * 2 = 0.8 # 0
.....

从上面结果可以看出,0.1 的二进制为:

0.0001100110011001100110011001100110011001100110011...

这是一个二进制无限循环小数,但计算机内存有限,我们不能储存所有的小数位数。那如何解决呢?

答案就是从末尾某个位置截断,直接取近似值,因此,在目前大部分编程语言(支持处理器浮点运算)中,浮点数都只能近似地使用二进制小数表示。

很多人使用 Python 的时候都不会意识到这个差异的存在,因为 Python 只会输出计算机中存储的二进制值的十进制近似值。但我们要牢记,即使输出的结果看起来好像就是 0.1 的精确值,实际储存的值只是最接近 0.1 的计算机可表示的二进制值。

解决方式

1.decimal

decimal 模块可以进行十进制数学计算,我们将浮点数转成字符串进行运算。

from decimal import Decimal

a, b = Decimal('0.1'), Decimal('0.2')
a + b == Decimal('0.3')

out:True

2.numpy.float32

numpy 模块中的32为浮点型保存数据。

import numpy as np

temp = np.array([0.1, 0.2, 0.3], dtype=np.float32)
temp[0] + temp[1] == temp[2]

当然体高精度的同时,性能可能会降低,在实际应用中这些近似值造成的细微偏差可能不会造成什么影响。如果碰到了留个心眼就好!

说了这么多,总结出一句话就是:浮点数转二进制时丢失了精度,计算完再转回十进制时和理论结果不同。不知道大家get到了吗?



这就是今天要分享的内容,微信搜 Python新视野,每天带你了解更多有用的知识。更有整理的近千套简历模板,几百册电子书等你来领取哦!

【版权声明】本文为华为云社区用户原创内容,未经允许不得转载,如需转载请自行联系原作者进行授权。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。