浮点数无法精确表示大多数十进制小数,因二进制下它们是无限循环小数,ieee 754 标准强制截断导致固有舍入误差,故 0.1 + 0.2 ≠ 0.3 是必然结果,非 bug;金融等需精确场景应改用整数运算或字符串处理。

因为二进制无法有限位表示大多数十进制小数,float 和 double 只能存储近似值,不是“存不准”,而是“根本存不了”。
IEEE 754 标准决定了它只能近似
浮点数在内存里按符号位、指数位、尾数位三部分编码。比如 double 有 52 位尾数,最多表达约 15–16 位十进制有效数字——但这不等于“能精确表示任意 15 位小数”。关键在于:十进制小数转二进制时,很多会变成无限循环小数。
-
0.1的二进制是0.0001100110011...(无限循环),必须截断到 52 位,产生固有舍入误差 - 同理,
0.2、0.3、0.675等都无法精确表示 - 这种误差在赋值瞬间就已固化,后续所有运算都基于这个近似值展开
为什么 0.1 + 0.2 != 0.3 是必然结果
这不是 bug,也不是编译器问题,而是两个近似值相加后,结果仍是一个近似值,且与 0.3 的近似值不一致。
-
0.1存成 double 后实际是0.10000000000000000555... -
0.2存成 double 后实际是0.20000000000000001110... - 两者相加得
0.30000000000000004440...,而0.3本身存的是0.29999999999999998889... - 所以
==比较返回false—— 它们确实是不同的比特模式
用 std::round 也救不回来
很多人想“四舍五入一下就好”,但 std::round 作用对象是内存中那个已经失真的值,不是你心里想的那个十进制数。
-
std::round(2.675 * 100) / 100得到2.67而非2.68,因为2.675存入double后实际是2.6749999999999998 - 缩放+舍入操作只是把误差从低位挪到高位,没消除源头
- 真正可控的四舍五入必须绕过浮点表示:用字符串解析或整数单位(如 cents)做运算
什么时候该警惕这个“不能精确”的本质
最容易被忽略的不是“计算不准”,而是“类型语义错配”——你把它当精确量用,但它天生就是近似工具。
- 金融计算:别用
double amount = 19.99,改用long long cents = 1999 - 配置精度输出(如保留两位小数):别靠
std::setprecision(2)掩盖,先确保原始值是可控整数倍 - 循环累加计数(如定时器 tick):
for (double t = 0; t 极可能多跑或少跑一次 - 哈希/键比较:把
double当std::map键?误差会让查找失败
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











