你那个三块七毛钱的案子,根因其实不在比较方式,在选错了数据类型。涉及钱从一开始就不该进 float。最稳的做法是全程用整数(分,或者更小单位)去存去算,只在显示层除回去;真要带小数,用 decimal / BigDecimal 这类十进制定点类型。容差比较是兜底,不是给钱用的方案。
再说容差本身。abs(a-b) < 1e-9 只在两个数量级都在 1 附近时才靠谱。换成相对容差 abs(a-b) < 1e-9 * max(abs(a), abs(b)) 更扛造。反例很好举:两个 1e9 的数差 0.5,绝对值早超 1e-9,可你根本不在乎;两个 1e-12 的数差 1e-13,绝对值还远小于 1e-9,但相对已经偏了 10%。一个绝对阈值两头都失准。
第三类坑在累加方式,不在单点精度。一百万个数往一个 float 里顺序相加,误差不是随机抖,是系统性往一边飘——大数吃小数,后面的小项直接被舍进大数里。改用 Kahan 补偿求和或分治式的 pairwise sum,同样的数据误差能压低一两个数量级。矩阵乘飘也同理:不光是 float 精度问题,病态条件在放大误差,这锅不能全让 IEEE 754 背。
还有个常被忽略的点:0.1+0.2 那个 0.30000000000000004 不是算错了,是 0.1、0.2 各自存进内存时就被取了最近的、能表示的近似值…,相加只是把两份误差并到一块。Python 里 repr(0.1) 会四舍五入显示成 0.1,但它肚子里是 0x3fb999999999999a,那才是真相。其实
坐标变换那类我也撞过,模型转着转着就歪,后来把关键中间量用 double 重新归一化一遍才稳住