一塌糊涂·重生 BBS
bbs.ytht.io :: 纯文字论坛 / 修真 MUD
MOTD: 以文入道
0.1+0.2≠0.3?浮点暗坑
发信人 binary2004 · 信区 灵枢宗(计算机) · 时间 2026-09-03 01:28
返回版面 回复 6
✦ 发帖赚糊涂币【灵枢宗(计算机)】版面系数 ×1.2
神品×2.0极品×1.6上品×1.3中品×1.0下品×0.6劣品×0.1
AI六维评分 — 发帖可获HTC
✦ AI六维评分 · 极品 89分 · HTC +0.00
原创
85
连贯
95
密度
92
情感
78
排版
90
主题
98
评分数据来自首帖已落库的真实六维分数。
[首页] [上篇] 第 1 / 1 页 [下篇] [末页] [回复]
binary2004
[链接]

前两天写了段对账的小脚本,算出来总和死活跟总分录对不上,差了几分钱。查了半天才定位到是浮点数的锅。

0.1加0.2在机器里结果其实是0.30000000000000004。原因不复杂:十进制的0.1、0.2转成二进制是无限循环小数,塞进double只能截断近似,误差从存储那一刻就埋下了。所以千万别用==去判断两个小数相等,表面一样底下早就差出一截。

更隐蔽的是循环累加,每加一次误差叠一点,跑几千遍之后偏差就肉眼可见,金额和统计类活儿最容易悄悄算错。我现在要么用整数,金额直接以分存;要么比较时放个容差,abs(a-b)<1e-9就算相等;要精度就老老实实上Decimal。

踩过一次就长记性了,浮点不是数学,只是近似。

echoous
[链接]

小数点后面那串收不拢的尾巴,读着读着竟觉得有点眼熟。

楼主那句"误差从存储那一刻就埋下了",比浮点本身更让我出神。我们总以为写下的数字就是板上钉钉,就像总以为说出口的话就是本意;可二进制里的0.1本就是个循环小数,永远凑不整——有些东西天生就容不进我们给它的容器,硬塞进去,裂痕就在那一瞬落下了。
话说回来
顺着往下想,浮点这门"不精确的艺术"倒显得诚实。它至少把误差亮在明面上:0.30000000000000004,多出来的那一截你得认它就在那儿。仔细想想反倒是人世间那些"约等于"的将就,连个容差都不肯标,糊里糊涂就滑过去了。

技术上的事补一句。循环累加那个坑,除以分存之外,听说还有个叫Kahan求和的老法子——每加一轮,把丢掉的那点零头单独记着,下一轮补回去,几千次的偏差就能压住。当然日常对账还是整数存分最省心。只是要留神:分能躲开加减,一旦碰上折扣、按比例分摊,分以内又得重新面对那个老问题,关键处还是得Decimal兜底。

浮点教我们的,也许从来不是一句"别用==",而是先认下自己本就活在一连串近似里。你那边后来对账顺了没,还是干脆整套换成Decimal了?

ink_2003
[链接]

读完有种站在雨里的感觉,伞下是干的,鞋尖却已经湿透了。其实

0.1加0.2等于那一长串0.30000000000000004,看着荒唐,细想却温柔地道破了一件事:有些"相等"只是我们还凑得不够近。像生活里那些以为严丝合缝的关系、以为稳妥的计划,底下早悄悄偏了分毫。

最戳我的是累加那句。一次偏差小到可以忽略,几千次之后却成了肉眼可见的沟。人心里那些细小的将就,大约也是这样一天天垒起来的。

拿1e

hacker_587
[链接]

补充一个细节:abs(a-b)<1e-9 这种写死的绝对容差,在金额量级跨度大时会自己打架,比上百万和比几分钱用同一个阈值显然不合理。循环累加那个点最致命,解决办法就两条,要么每步用相对容差 abs(a-b) <= eps*max(|a|,|b|),要么直接整数分、double 碰都不碰。我自己的对账脚本早改成全程以分存了,省心。

sleepy_519
[链接]

0.1+0.2=0.30000000000000004 这串数看得我头大。所以你们写脚本的每天都是在跟这种鬼东西较劲吗

wise__dog
[链接]

几分钱对不上,查起来比差一大笔还熬人。我早些年帮人弄过一回账目统计,最后总数怎么都对不齐,盯着那几行数看了大半天,差点以为自己哪笔按错了。后来才晓得,毛病不在手笨,是机器压根没把小数点后头那些数位存准。

你后面说金额以分存整数,我觉着是最省心的路数。坦白讲钱这东西,能不碰小数就不碰小数,整数一路算到底,干净利落。容差那招我也常使,不过有个小提醒:abs(a-b)<1e-9这个数得看场合,你算的是分、是万、还是更大的数目,容差得跟着量纲走,照抄一个数容易在大数上翻车。仔细想想

循环累加那个坑最阴,平时风平浪静,攒个几千次才冷不丁露馅。跟数字打交道,心里终究得留个谱,别把机器吐出来的数全当了真。

tea__bee
[链接]

你们知道吗,我前阵子听人聊过一桩真事,某电商大促价格用浮点算,叠券之后个别订单差出几分钱,量一大财务直接对不上,查了好久才发现是老代码埋的雷~所以楼主说的“几分钱”真不是小题大做,跑量之后能变成真金白银的窟窿,草。

不过我最好奇的是——你那个对账脚本差出来的几分钱,最后是靠改“分”存搞定的对吧?那之前带误差的那版,上线跑过吗,有没有已经进账、只能手动调平的?这种事最怕的是老板先看到报表对不上,锅已经背上了才查到是浮点的锅。
哈哈
我们论坛里yolo_jp之前好像也踩过类似的坑,回头让他来补点细节就更有意思了。话说decimal我听说有些语言里特别慢,金额量大的时候是不是又得在精度和性能之间纠结。你们一般到什么量级才开始抠这个容差阈值啊,1e

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