"浮点数判等"完美的解决方案吗?

浮生若梦的编程
  • 2.8k

2015/6/29
描述: 在各种语言中,由于遵循了浮点数标准,导致在"浮点数判等"使用"== !="都是错误的
措施: 目前看到的都是floatNum1 - floatNum2 > 一个精度标准,如果把浮点数转换为int(int判等很简单),则会引起许多意料之外的"隐式转换"错误. 前一种则让人感觉不完美.

难道没有完美的解决方案吗?

StackOverFlow相关问题

回复
阅读 3.9k
2 个回答
✓ 已被采纳

浮点数在计算中途的任何时刻,其有效数字的位数都是固定的。都用不着举很复杂的例子:

  1. 拿出一个步骤多一点的公式;
  2. 输入一个N个有效数字的随机十进制数;
  3. 先按照数学的方法计算出准确的结果;
  4. 再模拟计算机的浮点数算法,严格分步计算,每一步算出后都只保留固定的N个有效数字;
  5. 比对一下最终的结果会差多少——这个结果会让人大吃一惊的。

对于计算机的浮点数,只不过是十进制换成了二进制而已,本质上没有区别。

实际上从数学的角度上,加减乘除幂等各种运算,实际上都极易引起有效数字的剧烈膨胀:

  • 极大数加减极小数,容易引起有效数字数量的增长;(1E10 - 1,有效数字从1瞬间涨到9)
  • 乘法,有效数字翻倍;
  • 除法,分数结果极易在某种进制下除不尽;
  • 非整数幂和三角函数,易出现无理数;

从信息的角度来讲,数学运算极易直接导致信息熵的增长。即你需要更多的信息量来把这个数表达准确。信息熵增长,而一个浮点数的存储空间却永远不会变化,那么精度的损失就是必然的。

而计算又是无情的。有效数字越算越多,那么不可信的数字也会越算越多。哪怕是最末尾只有1位不可信——平方就是两位,立方就是4位。

也就是说,浮点数的反复运算最终只会产生3种结果:

  • 计算全步骤中,精度绝对够用,得到准确的结果。(几乎不可能发生)
  • 计算最后,有效数字把不可信数字全部顶出存储区。虽然不准确,但结果中的数字都是有效的。(几乎不可能发生)
  • 精度不够,同时计算过程中引入一定的误差扩散,造成结果末尾的若干位不准确。(实际工程中100%发生,没有任何例外)

在以上这些前提下,机械比较浮点数每个数位的==运算符实际上必然撞到无效数字的存储区,造成“末尾误差部分数字不一致”推翻“前边有效数字部分一致”的错误判断。

这自然是不可行的。


数学是完美的,但机器总是近似的,我们人类要充分的理解和尊重他。能通过研究和设计,把误差的扩散控制在可容忍的范围之内,索取到所需精度的结果,就已经是一件莫大的恩惠。

在理解这个过程的前提下,形式不是什么性命攸关的问题。想满足人类视觉观感的完美欲,说真的,其实并不算难:

  • 重载==运算符
  • 使用函数:cmp(f1, f2, precision = 1e-5)
  • 使用静态代码扫描,直接抓出==比较浮点数的误用

楼上的答案已经很明确了,没有。

当然,如果你是在Mathematica中编程,那么实数可以判相等。。

举个简单的例子吧,ln(e)在数学上是等于1的,但是如果用计算机来算,e是近似的,ln的计算也是近似的(不然要么存无限位数要么计算无限的时间),因此结果当然是近似的,肯定不等于1,所以需要设定一个误差。

你可以用python输出一下0.1+0.2看看结果。。。。

你知道吗?

宣传栏