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

今天又让浮点数给坑了 翻出一段老代码 里面居然拿 == 直接比两个小数 我盯着屏幕愣了好几秒

说起来0.1+0.2在大部分语言里算出来是0.30000000000000004而不是0.3 这真不是语言有bug 根子上是二进制压根没法精确表示0.1和0.2 转过去就是无限循环小数 跟十进制里1/3写成0.33333…一个道理 位数有限存不下 误差就跟着来了

所以拿==直接比较两个浮点数基本是在埋雷 正经写法是用误差范围判断 abs(a-b)<1e-9 差不多就得了 别跟它较真

笑死还有个更阴的是循环累加 我之前写统计脚本 跑了几万次加法 结果偏出去快一块钱 查半天才反应过来是累积误差 涉及金额这种敏感场景老老实实用整数 以分为单位存 或者上Decimal 别跟浮点死磕

这玩意儿看着不起眼 真踩进去能让你debug到怀疑人生 大伙儿写业务多留个心眼哈

logic90
[链接]

固定 1e-9 当判断阈值其实值得商榷:数字很大时它相对太小会误判不等,很小又太宽松。量级差异大时还是用相对误差 abs(a

gauss_2004
[链接]

关于拿 1e-9 当通用容差,我想补一个角度:这是个绝对容差,不随量级缩放。IEEE 754 双精度 53 位尾数,eps ≈ 2.2e-16,量级到 1e9 时一个 ULP 已经约 2.2e-7,比 1e-9 大两百多倍。也就是说在亿级数字上,两个相邻可表示值差了 2e-7,拿 1e-9 判等永远判不进,因为容差比数值本身的刻度还细,等于没意义。

更稳的是相对容差:abs(a-b) <= max(|a|,|b|) * eps,或者直接调现成函数,比如 Python 的 math.isclose 默认 rel_tol=1e

tender_2006
[链接]

盯着屏幕愣住那一下太真实了,我前阵子也被精度问题绊过,查到半夜才回过神。金额这种还是用整数以分存最踏实。

bookworm_96
[链接]

固定阈值1e-9那句我补一句:数比它大很多或小很多时都会失灵。更稳是比相对误差 abs(a

quant
[链接]

想起自己前年踩过的坑。当时在跑一个数值积分的小程序,每一步都往总和里加一个很小的增量,迭代了上百万次。收工一看,总和和解析解差了快百分之三。嗯我第一反应是公式写错了,重读三遍才发现是 cumulative error——那点微不足道的误差被放大了上百万倍。

楼主说的 epsilon 比较我认同,不过 1e-9 这种写死的绝对值不是哪儿都灵。浮点在大数附近的“最小可分辨间隔”会变宽,两个数看着该相等、实际差可能甩 1e-9 好几条街。更稳的是相对误差 abs(a-b) <= eps * max(|a|,|b|)。日常小数字无所谓,别把它当 silver bullet 就行。

涉及钱那段我完全同意,以分存整数最干净。

euler_cat
[链接]

关于那个 abs(a-b)<1e-9 的写法,我倒想多说两句。übrigens 这个 1e-9 是个挺随意的数,跟具体场景没什么逻辑上的必然联系。浮点比较真正麻烦的地方在于,误差是跟着量级走的——你要比的两个数本身就在 1e-9 附近,这个阈值就太松了;要是一万块的体量,1e-9 又紧得没道理。更稳的思路是用相对误差,或者先想清楚这两个数从哪来、经过了几道运算再定容差,而不是随手抄一个 magic number 上去。

顺带提一句,Decimal 也不是万能药。Python 的 Decimal 默认 28 位有效数字,超了照样截断,它只是把"十进制里本不该丢的"保住了,本质还是有限精度。真碰上金额,整数以分为单位存才是真正省心的,Decimal 顶多算个过渡方案。其实

想起前阵子帮人看个脚本,循环累加跑了几十万次,偏出去的量级跟你说的那次差不多。当时也是先怀疑上游数据有问题,后来看 traceback 才反应过来是累积误差在慢慢爬。这种 bug 最磨人,它不报错,只是悄悄把结果挪了位置。严格来说

写业务的时候,涉及"相等"判断的地方多停一秒,往往比事后 debug 便宜得多。

hacker_de
[链接]

固定阈值 1e-9 只在数值量级接近 1 时靠谱。值上亿或贴着零,abs(a-b)<1e-9 照样翻车。更稳的是相对容差 abs(a-b) <= 1e-9*max(|a|,|b|)。我之前那个统计脚本就是栽在这,后来全改成 math.isclose 了。

lyric__cn
[链接]

盯屏幕愣住那几秒,我跟着也呆了一下。说实话

浮点这种"不精确"细想其实有点迷人——我们总默认数字是最诚实的东西,结果机器在二进制里悄悄偏了半步,把0.1和0.2都存成了永远差一点的模样。像有些话,意思总在传达的途中散掉些许,你追不回来,也不能说它错了。

想起谁写过,“精确有时是一种暴力”。怎么说呢decimal也好、以分为单位也好,不过是我们想把那口气重新憋回去的尝试。你不跟误差较真的时候,它反倒温柔。

elder77
[链接]

我年轻那会儿也在这上头栽过跟头。有一回给人弄个小账目程序,图省事直接拿浮点存金额,跑了没多久对账就对不上,差个几分钱,逻辑翻来覆去查了半天没毛病,最后才反应过来是底下那点误差在作怪。

楼主说的以分为单位存整数,这个最实在,Decimal也行,敏感场景里真别跟浮点死磕。

不过有一点我倒想补一句:你说==比较基本是埋雷,这话大体没错,但也不是绝对的。有些时候两个数走的是同一条计算路径,比如同一个常量被反复引用,那种情况下偶尔比一比也不至于出大乱子。当然了,新手还是老老实实用误差范围最稳当,少给自己找罪受。

现在这些语言默认都这样,老辈人当年还拿纸笔算位数呢,想起来挺有意思的 (。・ω・。)

turing
[链接]

补充一个细节,帖里 abs(a-b)<1e-9 这个写法看着省事,但 epsilon 取多少其实得看场景,不是拍脑袋定个 1e-9 就万事大吉。double 的精度(ulp)是跟着数值量级走的,拿固定绝对值去比,遇到很大的数可能本来就该差出不止 1e-9,遇到接近 0 的数又显得太松。numpy 的 isclose 默认 rtol=1e

duckling90
[链接]

拿==比小数这坑我也踩过 那回对账对出几毛钱差 翻了俩小时才反应过来是浮点问题 从此金额一律转分存了

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