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

之前帮公司弄对账脚本,图省事直接拿 double 把几百笔订单金额累加,再跟系统总额比。逻辑看着没毛病,结果跑出来的差额是几分钱、几毛钱,时有时无,复现都复现不出来,差点被财务追着问。

根子就在 IEEE754。0.1+0.2 在浮点里根本不等于 0.3,二进制表示不了太多十进制小数,误差每累加一笔就偷偷攒一点。单笔看不出来,量一大就冒头,而且不是每次都冒,纯看脸。拿浮点直接 == 或者 != 比金额,基本是在给自己挖坑。

后来老老实实改成用整数分来存钱,或者上 decimal/定点数,比较的时候也丢个 epsilon 容差,不再裸比。一句话,钱这东西碰都别用浮点直接碰。我这种做外贸的,账对不上可不是闹着玩的,面包要紧。btw 现在凡是涉及钱的字段,一律整数处理,绝不手软。

daemon
[链接]

你最后那句"纯看脸"得纠一下。IEEE754 的舍入是 deterministic 的,一点都不随机。复现不出来是因为你没把那几百笔的输入顺序和具体数值固定住——浮点每加一笔都按同一套规则丢低位,样本一换,哪几位翻车就跟着变,看着像抽签,其实随便抽一笔都能手算还原出来。
简单说
另一个点,比较时丢 epsilon 容差对钱属于治标。epsilon 是给物理量那种自带测量误差的场景用的。钱要的是 exact match,最稳还是整数分直接比相等,别拿容差去盖。decimal 没问题,但记住它只是把"分"这件事封装好了,除法和 round 的语义还得你自己定,不然照样翻车。

lyric87
[链接]

读着读着想起小时候数零钱,攥在手心里总觉得比记账本上多几枚,摊开一数又对不上。那种说不清的差额,跟你说的一个样,不是算错了,是它本来就在那儿,只是有时藏得住,有时藏不住。

你那句"纯看脸"真叫人心里一沉。最怕的就是这种看不见的偏倚,一点点攒着,平时温顺得像什么都没发生,冷不丁在你最信它的时候露一角。钱是这样,日子里的许多事大约也这样。

我后来但凡碰数字都先想清楚它到底是什么"单位",哪怕只给自己记个账。整数分这招确实干净,像是把模糊的水沥干,剩下的颗颗都踏实。

geek__jr
[链接]

epsilon 容差其实是治标,误差累积到一定程度照样越阈值。涉及钱还是整数分或 decimal 最稳,别拿浮点赌运气。

hamster_bee
[链接]

差几分钱还复现不出来最要命,闷头查到半夜不知道漏哪笔。整数分这招稳

bookworm_sr
[链接]

想补充一点,就是帖子里那句"改成整数分或者 decimal,比较时丢个 epsilon 容差"——整数分/定点 和 epsilon 其实是两回事,叠在一起用反而有点拧巴。

epsilon 容差是给浮点准备的退路。当你被迫拿 double 存金额、又必须判断两笔"相等"时,因为 0.1+0.2 不等于 0.3,直接 == 会翻车,才退而求其次比个差值小于阈值。可一旦你真把金额存成了整数分(元乘 100 塞进 int64 之类),或者用了真正的十进制定点类型(decimal 内部是十进制编码,不是二进制浮点),每一笔都是精确值,误差从源头就不存在了。这时候还挂个 epsilon,等于给自己留了个口子:一个真实差了一分钱的对账错误,会被容差悄悄吞掉,财务查账时更摸不着头脑。

所以更干净的是二选一,别叠 buff:要么全程整数分加精确比较,要么只在极少数甩不掉浮点的场景才上 epsilon,而且阈值得按业务最小币种显式定,比如半分,而不是随手写个 1e-9。

另外"每累加一笔就偷偷攒一点"方向不是单向的。二进制舍入有时进有时舍,累计误差可能部分抵消,这也解释了你遇到的"时有时无、复现不出来"。double 有 53 位尾数,约 15–17 位十进制精度,小账期内误差通常极小,量一大或者撞上某些特定数值组合才露头。你们做外贸多一道汇率换算,那层的舍入点也得单独钉死,不然浮点坑填平了、汇兑那层又漏了。

sweet2006
[链接]

0.1+0.2 不算出 0.3 这点最扎心,我以前也听人说过类似的坑。最怕的还是误差时有时无、复现不出来,财务一追问真是有嘴说不清。改整数分就踏实了,钱的事经不起半点侥幸。

penguin26
[链接]

被财务追着问那段太有画面了哈哈哈 我之前写代码也踩过0.1+0.2这个坑 还以为是自己哪行逻辑写岔了 查半天发现是浮点在背刺 后来涉及钱的全改整数分 一点不含糊 钱这东西真不能跟浮点讲道理

nosy
[链接]

等等,你一个做外贸的还自己撸对账脚本?我怎么听说的版本是这种小公司老板基本都身兼会计加半个码农,你该不会也是深夜自救型吧……这账真对不上可比那几分钱吓人多了,你们那批订单量大吗~

root_ism
[链接]

顺着你这个帖子补一个细节:你说的"纯看脸"其实不准确。浮点误差是确定性的,0.1+0.2 在任何符合 IEEE754 的机器上跑出来永远是同一个固定的错值,不是抽卡。复现不出来,是因为误差累积量完全取决于累加顺序和每笔具体金额,哪些组合会越过四舍五入的临界点、什么时候冒头,是跟着数据走的,拿不对的测试数据自然撞不到。

关于 epsilon 再多嘴一句:容差这东西是给"还得用 float 但暂时改不动"的场景兜底的。你既然已经整数分了,比较就直接 ==,别再塞容差。整数比就是精确相等,多此一举加 epsilon 反而把"账平了"这个语义弄模糊。要么整数分一路到底,要么上 Decimal 固定精度,别两个混着来。

我早年写对账也栽过这坑,后来所有金额字段一律用整数存分,显示层才除。干净,省心。

lazy_cat
[链接]

0.1+0.2不等于0.3这也太离谱了 我天天剁手的人看完都不敢对账了哈哈

acid_573
[链接]

这坑踩过的人能开互助会了。无语我以前算账也迷信过自动公式,对到半夜才发现是几分钱的幽灵误差在捣鬼。

roast75
[链接]

0.1+0.2 不等于 0.3 这个坑真是一踩一个准,我头回听说的时候也愣了半天。你帖里最要命的是"复现都复现不出来"那段——能稳定报错的 bug 都算温柔了,这种看脸才冒头的才叫折磨,财务追过来你连自证清白的材料都掏不出 (;´д`)

不过说真的,你后面"比较也丢个 epsilon 容差"这句我有点不同看法。既然都整数分存了,比的时候其实该直接等于,容差反而容易把真差错也一起容过去。epsilon 适合本来就是近似值的物理量,金额不是近似的。当然外贸还有汇率换算那层,该四舍五入的地方另说。

你那句"面包要紧"总结得实在,比起优雅的代码,财务不找上门才是真 KPI

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