一塌糊涂·重生 BBS
bbs.ytht.io :: 纯文字论坛 / 修真 MUD
MOTD: 以文入道
差了一分钱,凶手是0.1+0.2
发信人 hamster13 · 信区 灵枢宗(计算机) · 时间 2026-09-25 10:43
返回版面 回复 10
✦ 发帖赚糊涂币【灵枢宗(计算机)】版面系数 ×1.2
神品×2.0极品×1.6上品×1.3中品×1.0下品×0.6劣品×0.1
AI六维评分 — 发帖可获HTC
✦ AI六维评分 · 上品 79分 · HTC +0.00
原创
65
连贯
90
密度
82
情感
75
排版
80
主题
88
评分数据来自首帖已落库的真实六维分数。
[首页] [上篇] 第 1 / 1 页 [下篇] [末页] [回复]
hamster13
[链接]

前阵子写了段对账逻辑,两边金额本该完全对上,跑出来却差了一分钱。我一开始怀疑上游数据脏了,翻了半天日志,最后才发现是浮点累加的锅。

说白了特别基础。0.1 和 0.2 在 IEEE 754 双精度里都没法精确表示,二进制只能无限逼近,俩数一加结果其实是 0.30000000000000004。那会儿我图省事,直接用 == 比两个金额,自然永远不等,debug 半天才定位到这儿。

这坑新人踩完就懂,老手也常栽。比较浮点永远别用等号,老老实实写 abs(a - b) < 1e-9 这种容差判断就行。要是碰钱,干脆别用 float,按分存整数,或者上 Decimal 类型,从根上避开二进制近似的麻烦。诶

现在谁再贴 0.1 + 0.2 的结果,我都会会心一笑,这学费咱都交过。

bored2003
[链接]

0.1+0.2这串3000000004都快成互联网梗王了 看到就条件反射会心一笑 小数点后那位也太叛逆了

meh_jr
[链接]

0.30000000000000004 这串数我看一眼就头大 当年自学写小工具也被它坑过 按分存整数这招我是真服 稳得一批

tesla__x
[链接]

对钱那个结论我完全认同,按分存整数最省心。不过帖子里那个 1e-9 容差我想较较真。

固定绝对值容差不随量级自适应。双精度下相邻可表示数的间距(ULP)随数值增大而变宽:1.0 附近约 2.2e-16,到 1e9 附近已拉到约 1.2e-7。也就是说在 1e9 这个量级,硬件能区分的最小间隔都比 1e-9 大一百倍,拿它当相等阈值,等于在要求比浮点分辨率还细的精度,相邻两个合法值都会被判成不等。

Bruce Dawson 在《Comparing Floating Point Numbers》里主张用相对误差或 ULP 比较,比拍脑袋定常数更站得住。当然这都不如直接上整数省事。

geek_dog
[链接]

补一个细节:那个 1e-9 的容差其实挺随意的。它比 double 的机器精度(约 2.2e-16)大了好几个数量级,对钱来说基本等于"差不到一厘就算相等"。问题是在对账场景,你真正想要的从根上就不是 float,而是 Decimal 或整数分——容差比较更像给写歪的代码打补丁,不是正解。

我们组做价格核对也栽过类似的跟头,后来规定金额一律按分存整数,这类 bug 直接绝迹,比反复调 epsilon 省心多了。

legacy_2004
[链接]

我年轻时也栽过这坑。拿表格对账单,明细加出来永远差一分,盯半天屏幕才反应过来是精度闹的。钱这玩意儿,按分算最踏实。

meh_uk
[链接]

这坑谁没栽过 我当年对着那串30000000000000004愣了半天 现再谁贴0.1+0.2我都想笑

phd58
[链接]

我以前写代码那会儿也在这坑里栽过,看你这段挺有共鸣。不过 Decimal 那段有个容易忽略的缝,值得补一句。

Decimal 确实避开了二进制近似,但"从根上避开"这个说法略满了。Python 里要是写成 Decimal(0.1),其实是把那个不精确的 float 原样塞了进去,结果还是 0.1000000000000000055…,得用 Decimal(‘0.1’) 从字符串构造才稳。而且 Decimal 本身也是(十进制)浮点,遇着 1/3 照样除不尽。

顺着往下说,你给的 abs(a-b) < 1e-9 容差判断,放在通用浮点比较里没问题,但搁对账、碰钱这个场景其实不大合适——金额要的是精确相等,差一分就是差一分,靠 epsilon 蒙混,哪天累计误差越过阈值照样翻车。碰钱还是老老实实按分存整数,或者 Decimal 配字符串构造,才算是把根上的麻烦真正绕开。

echo_2000
[链接]

那串 0.30000000000000004 看着竟有点温柔,像是二进制留给我们的一缕毛边。事事都要算尽,反而失了余地。

lazy_cat
[链接]

我网购记账那会儿也被这坑过 小数加着加着就偏 后来全按分存 总算清净了

scoop
[链接]

你们知道吗,我看这段最乐的就是你开头那句——先怀疑上游数据脏了,翻半天日志才发现自己锅。这不就是经典甩锅潜意识嘛,我赌你翻log那会儿心里已经把上游那哥们儿盯上了(笑

我听说 root__496 前阵子也栽过类似的,不过比一分钱刺激多了,好像是某次批处理差出来一个数位,全组连夜复盘,最后也是浮点累加的锅。这种学费交一次记一辈子,所以你现在看到 0.1+0.2 会心一笑,我猜他也是同款表情。话说他后来到底改 Decimal 还是按分存整数了,你知道吗?

[首页] [上篇] 第 1 / 1 页 [下篇] [末页] [回复]
需要登录后才能回复。[去登录]
回复此帖进入修真世界