Floating point值是不精确的,这就是为什么我们应该很少在比较中使用严格的数字相等。例如,在Java中,这会打印false
(as seen on ideone.com):
System.out.println(.1 + .2 == .3);
// false
通常,比较浮点计算结果的正确方法是查看某些预期值的绝对差值是否小于某些容差epsilon。
System.out.println(Math.abs(.1 + .2 - .3) < .00000000000001);
// true
问题在于某些操作是否可以产生确切的结果。我们知道,对于任何非有限浮点值x
(即NaN
或无穷大),x - x
为ALWAYS NaN
。
但如果x
是有限的,那么这是否有保证?
x * -1 == -x
x - x == 0
(特别是我对Java行为最感兴趣,但也欢迎其他语言的讨论。)
对于它的价值,我认为(我可能在这里错了)答案是是!我认为它归结为是否有任何有限IEEE-754浮点值,它的additive inverse总是可以精确计算。从例如float
和double
有one dedicated bit just for the sign,这似乎是这种情况,因为它只需要翻转符号位来找到加法逆(即significand应该留下完整的)。
答案 0 :(得分:3)
IEEE 754浮点保证了两个等式,因为x-x
和x * -1
的结果都可以表示为与x
具有相同精度的浮点数。在这种情况下,无论舍入模式如何,都必须通过兼容的实现返回确切的值。
编辑:与.1 + .2
示例比较。
您无法在IEEE 754中添加.1
和.2
,因为您无法将其代表传递给+
。加法,减法,乘法,除法和平方根返回唯一的浮点值,该值取决于舍入模式,紧接在上面,最接近处理关系的规则,...,操作的结果 R 中的相同参数。因此,当结果(在 R 中)恰好可以表示为浮点数时,无论舍入模式如何,此数字都会自动生成结果。
您的编译器允许您编写0.1
作为不带警告的不同可表示数字的简写这一事实与这些操作的定义正交。例如,当您编写- (0.1)
时,-
是准确的:它返回与其参数完全相反的结果。另一方面,它的参数不是0.1
,而是编译器在其位置使用的double
。
简而言之,操作x * (-1)
准确的另一部分原因是-1
可以表示为double
。
答案 1 :(得分:2)
虽然x - x
可能会为您提供-0
而不是真0
,但-0
与[{1}}相等,因此您可以安全地假设任何有限数字减去自身将比较等于零。
有关详细信息,请参阅Is there a floating point value of x, for which x-x == 0 is false?。