for循环中i += 0.1会死循环,是因为0.1在IEEE 754双精度下无法精确表示,其二进制为无限循环小数,每次累加引入微小舍入误差,经多次累积后i始终无法精确等于预期值(如10.0),导致条件i!=10永不成立。

浮点数循环累加无法靠 == 或简单四舍五入“控制精度”,必须换数据类型或重构逻辑。
为什么 for i += 0.1 会死循环?
因为 0.1 在 IEEE 754 float64 中无法精确表示,二进制下是无限循环小数。每次加法都引入微小误差,100 次后累积偏差可能让 i 永远达不到预期终点(比如 i 始终为真)。
- 错误写法:
for i := 0.0; i → 极大概率死循环或提前/延后退出 - 正确思路:用整数计数器驱动,再按需转为浮点值,如
for j := 0; j - 若必须用浮点变量做边界判断,改用误差容忍:
math.Abs(i-10.0) > 1e-9替代i
累加过程中如何避免误差滚雪球?
连续 += 会让每次舍入误差叠加,尤其在大量迭代或跨数量级数值混合时。Kahan 求和算法能显著抑制该问题,但 Go 标准库未内置,需手动实现。
- 基础累加(不推荐):
sum += x[i]→ 误差随n线性增长 - Kahan 求和(推荐):
sum, c := 0.0, 0.0;循环内:y := x[i] - c; t := sum + y; c = (t - sum) - y; sum = t - 注意:Kahan 不消除单次浮点表示误差,只减少累加过程中的舍入损失
- 对金融等场景,直接弃用
float64,改用apd.Decimal或big.Rat
toFixed 类函数为什么不能解决累加精度问题?
toFixed 是对单个值做字符串格式化再解析,本质仍是 float64 运算,无法修复底层表示缺陷。它只影响显示或临时截断,不改变参与计算的数值本身。
- 错误依赖:
sum = toFixed(sum + x[i], 2)→ 每次仍用不精确的sum + x[i]计算,再“修脸”,误差已发生 - 真正可控的方式:全程用整数(如金额存分为单位)、或任意精度库(
apd、big.Rat) -
apd.Decimal示例:sum.Add(sum, apd.New(123, -2))(表示 1.23),无二进制漂移
最易被忽略的一点:误差不是“偶尔出现”,而是只要涉及 float64 的循环累加,就必然存在——区别只在于是否在你的业务容忍范围内爆发。别指望靠调大 epsilon 或多截几位小数来掩盖,该换类型时就得换。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











