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

前两天看人贴了一段对账代码,循环里累加金额,跑完差了一分钱查不出原因。这锅得甩给 IEEE 754。0.1 和 0.2 在二进制底下根本没法精确表示,都是无限循环小数,0.1+0.2 实际算出来是 0.30000000000000004,跟 0.3 不相等。直接在代码里写 if (a == b) 去判断两个浮点数相等,或者指望一个 for 循环累加出精确结果,迟早爆雷,而且往往上线跑一阵子才暴露,特别难 debug。

金额这类场景老实说就该用整数分或者 Decimal 定点数。真要做浮点相等比较,取个误差范围 abs(a-b) < eps 比裸 == 靠谱得多。eps 也别瞎设 1e-10,得看量纲,量很大时这个阈值根本兜不住。

这种坑老手也未必每次都避得开,写的时候多留个心眼就少半夜被叫起来救火

newton97
[链接]

eps 那块想接着说一句,固定阈值其实没区分绝对误差和相对误差。金额小的时候 abs(a-b) < 1e-8 还凑合,可一旦跑到千万量级,1e-8 跟有效数字比基本等于没设门槛。要稳还是用相对容差 abs(a-b) <= eps * max(abs(a), abs(b)),或者上 Decimal 时把上下文精度和舍入模式显式定下来,否则 Decimal 做除法照样会留下无限循环的小尾巴。

之前看人那个对账脚本就是栽在这,float 累加换成整数分之后那一分钱直接没了。

lol_kr
[链接]

0.30000000000000004这串数真够赖皮的 跟赖账死活不凑整似的

hamster13
[链接]

草,这坑我踩过,对账差两分钱查到凌晨三点。后来全改成用分存整数,世界清净了

salty_853
[链接]

对着 0.1+0.2 算出来那一长串 0.30000000000000004 发呆的人可不止你一个,说真的我刚自学那阵还以为自己机器坏了。帖主把"老老实实用整数分"甩出来算把救命绳递到手边了,多少对账脚本都是懒得换类型才半夜炸的。

aurora_529
[链接]

楼主说的那一分钱,像深夜里一个走失的小数,安安静静地躺在账目对不上的缝隙里。

我读到0.1在二进制底下是无限循环的时候,心里莫名咯噔了一下。我们用来衡量价值、丈量日子的那些数字,在机器最深处竟然都到不了尽头——永远差那么最后一小口,永远合不拢。有一说一这有一种很宿命的东西。表面上看,0.30000000000000004和0.3几乎是一回事,肉眼、人手、乃至多半时候的直觉都分不出彼此;可账本不认直觉,它在那毫厘之间悄然地不平了。楼主说最怕的正是这种"看起来对",我深以为然。生活里多少说不清的误会也是这般,两个人说的明明是同一件事,底下其实差了那么一点点,平时不显,积久了就爆雷。

你开的方子都实在——整数分、Decimal、abs(a-b)<eps。我只想顺着eps多补一句。你说eps别瞎设1e-10,得看量纲,这一点特别对,而且它让我想起误差本身的脾气:小尺度上那个"几乎为零"的尾巴可以忽略;可一旦数字以亿计,原本被原谅的微小偏差就被放大成一道实实在在的鸿沟,怎么舍入也兜不回来了。人的耐心大约也这样,近处一点错位无伤大雅,距离推得越远,同样的误会就越难弥合。

Точность — вежливость королей,俄语里说精确是王者的礼貌。可二进制早把这礼貌撕开了一道缝。我们能做的,不过是给每一段尺度,挑一个诚实的 eps,然后承认世界本就由合不拢的循环拼成。
话说回来
下次再碰到对账差一分,大概会想起这个深夜里走失的数字吧。

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