"浮点数判等"完美的解决方案吗?
2015/6/29
描述: 在各种语言中,由于遵循了浮点数标准,导致在"浮点数判等"使用"== !="都是错误的
措施: 目前看到的都是floatNum1 - floatNum2 > 一个精度标准,如果把浮点数转换为int(int判等很简单),则会引起许多意料之外的"隐式转换"错误. 前一种则让人感觉不完美.
难道没有完美的解决方案吗?
可乐不珈冰
9 years, 9 months ago
Answers
浮点数在计算中途的任何时刻,其有效数字的位数都是固定的。都用不着举很复杂的例子:
- 拿出一个步骤多一点的公式;
- 输入一个N个有效数字的随机十进制数;
- 先按照数学的方法计算出准确的结果;
- 再模拟计算机的浮点数算法,严格分步计算,每一步算出后都只保留固定的N个有效数字;
- 比对一下最终的结果会差多少——这个结果会让人大吃一惊的。
对于计算机的浮点数,只不过是十进制换成了二进制而已,本质上没有区别。
实际上从数学的角度上,加减乘除幂等各种运算,实际上都极易引起有效数字的剧烈膨胀:
-
极大数加减极小数,容易引起有效数字数量的增长;(
1E10 - 1
,有效数字从1瞬间涨到9) - 乘法,有效数字翻倍;
- 除法,分数结果极易在某种进制下除不尽;
- 非整数幂和三角函数,易出现无理数;
从信息的角度来讲,数学运算极易直接导致 信息熵 的增长。即你需要更多的信息量来把这个数表达准确。信息熵增长,而一个浮点数的存储空间却永远不会变化,那么精度的损失就是必然的。
而计算又是无情的。有效数字越算越多,那么不可信的数字也会越算越多。哪怕是最末尾只有1位不可信——平方就是两位,立方就是4位。
也就是说,浮点数的反复运算最终只会产生3种结果:
- 计算全步骤中,精度绝对够用,得到准确的结果。(几乎不可能发生)
- 计算最后,有效数字把不可信数字全部顶出存储区。虽然不准确,但结果中的数字都是有效的。(几乎不可能发生)
- 精度不够,同时计算过程中引入一定的 误差扩散 ,造成结果末尾的若干位不准确。(实际工程中100%发生,没有任何例外)
在以上这些前提下,机械比较浮点数每个数位的
==
运算符实际上必然撞到无效数字的存储区,造成“末尾误差部分数字不一致”推翻“前边有效数字部分一致”的错误判断。
这自然是不可行的。
数学是完美的,但机器总是近似的,我们人类要充分的理解和尊重他。能通过研究和设计,把误差的扩散控制在可容忍的范围之内,索取到所需精度的结果,就已经是一件莫大的恩惠。
在理解这个过程的前提下,形式不是什么性命攸关的问题。想满足人类视觉观感的完美欲,说真的,其实并不算难:
-
重载
==
运算符 -
使用函数:
cmp(f1, f2, precision = 1e-5)
-
使用静态代码扫描,直接抓出
==
比较浮点数的误用
光をつかむ
answered 9 years, 9 months ago