0.1 + 0.2 为什么不等于 0.3:IEEE 754 到底存了什么

举报
yd_242458115 发表于 2026/11/14 12:16:40 2026/11/14
【摘要】 在大多数编程语言里打印 0.1 + 0.2,得到的是 0.30000000000000004。这不是程序的 bug,也不是语言实现得差——0.1 在二进制里本来就是无限循环小数。讲清 64 位浮点怎么存数、误差为什么正好落在那个位置,以及金额计算该怎么绕开它。

先看现象

在大多数语言里,这一行都不会如你所愿:

>>> 0.1 + 0.2
0.30000000000000004
>>> 0.1 + 0.2 == 0.3
False

JavaScript 一样:

> 0.1 + 0.2
0.30000000000000004
> 0.1 + 0.2 === 0.3
false

Java、C、Go、Ruby……只要用的是 IEEE 754 的双精度浮点,结果都一样。

这不是 bug,是这套表示法的必然结果。

为什么 0.1 存不准

十进制的小数位是「十分之一、百分之一、千分之一」,二进制的小数位是「二分之一、四分之一、八分之一」。

问题在于:有些十进制小数,用二进制根本写不出来。

  • 0.5 = 1/2 ✅ 写得出来
  • 0.25 = 1/4 ✅
  • 0.75 = 3/4 ✅
  • 0.1 = 1/10 ❌ 写不出来

因为 10 = 2 × 5,分母里带着一个 5,而二进制只能用 2 的幂。所以 0.1 在二进制里是:

0.0001100110011001100110011001100110011...

无限循环,就像十进制里 1/3 = 0.3333... 一样。

那它实际存的是什么

双精度浮点一共 64 位,切三块:

部分 | 位数 | 作用

符号位 | 1 位 | 正负

指数 | 11 位 | 数量级(能表示约 10^-308 到 10^308)

尾数 | 52 位 | 有效数字,精度就在这里

52 位尾数,能提供约 15~17 位十进制有效数字。

0.1 的无限循环二进制被截断到 52 位,存下来的其实是:

0.1000000000000000055511151231257827021181583404541015625

比 0.1 稍微大一点点。0.2 同理,也比 0.2 稍微大一点点。

两个「稍微大一点」相加,误差累加,结果就偏到了 0.30000000000000004。

这个误差有多大,会不会越滚越大

单次误差在 10^-17 量级,看起来微不足道。但它有两个要命的性质:

① 相等判断会失效

0.1 + 0.2 == 0.3      # False

两个数学上相等的值,用 == 比会不相等。这是最容易踩的坑。

② 累加会漂

total = 0
for _ in range(10_000_000):
    total += 0.1
print(total)
# 1000000.0000000188 左右,不是 1000000

一千万次累加,误差到了小数点后第 10 位。如果这是钱,就是实实在在的差账。

该怎么绕开

① 金额用整数存最小单位

不要用「元」存钱,用「分」:

price_cents = 1999          # 19.99 元
total = price_cents * 3     # 5997 分 = 59.97 元

整数运算没有精度问题,只在最后展示时除以 100。

② 需要精确十进制就用 Decimal

Python 的 decimal、Java 的 BigDecimal、C# 的 decimal,都是十进制表示,代价是慢一些:

from decimal import Decimal
Decimal('0.1') + Decimal('0.2') == Decimal('0.3')   # True

注意:要用字符串构造,Decimal(0.1) 会先把 0.1 变成浮点再转,误差照样进来。

③ 浮点数比较要带容差

abs(a - b) < 1e-9      # 而不是 a == b

Python 标准库给了 math.isclose(),很多语言也有对应的函数。

一个反直觉的事实

误差不只来自 0.1 这种「循环小数」,也来自大数加法:

>>> 1e16 + 1 == 1e16
True

因为 1e16 需要的位数已经超出 52 位尾数能精确表示的范围,加 1 直接被舍掉了。

所以浮点数的精度是相对的,不是绝对的:数值越大,能精确到的小数位越少。

落一句

0.1 + 0.2 != 0.3 不是哪个语言没做好,是用有限位二进制表示无限位十进制小数的数学后果。

只要记住一条:要精确的场合(钱、计数、ID)别用浮点,浮点只用来算测量值和科学计算。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

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

全部回复

上滑加载中

设置昵称

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

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

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