比较浮点值及其副本



我知道,如果两个doubles是从不同的计算中获得的,那么比较它们是有问题的。但是,当其中一个是另一个的副本(价值)时,这也适用吗。以下几行解释了该场景。如果我有这样的问题,

double a,b;
a=randdouble();/*some double value*/
b=a;

然后,

Q1)在C编译器(我有gcc 6.1.1)的情况下,比较a==b是否总是保证返回true

Q2)如果我使用malloc在堆内存中分配变量ab,上面的答案会保持不变吗?

Q3)如果我用JAVA编译器(我使用的是Open JDK 1.7.0)替换C编译器,并进行必要的语法更改,上面的答案会保持不变吗。

编辑1:数字ab!= NaN

Q1:不能保证比较结果为真,原因很简单,NaN与自身比较不相等。可能还有其他情况,但NaN是一个明显的反例。

Q2:变量在内存中的位置没有区别。

Q3:我希望Java也能有类似的表现。

撇开这种特殊情况不谈,我相信标准并没有给出这样的保证:

想象一个ABI,其中计算double表达式,并以80位精度(Intel 80x87堆栈)返回值,但存储为64位IEEE-754双精度。即使randdouble()被定义为返回double,而不是long double,其返回值也可能比存储在ab中的值更精确。根据编译器如何优化randdouble()函数调用和比较a == b之间的各种表达式,它最终可能会将80位的精确返回值与其通过转换为64位并返回到80位而获得的近亲进行比较。如果转换中丢失了精度,则比较将失败。我将尝试从标准中找到一个适当的参考来支持这一点,但这似乎是合理的,尽管ab是局部变量还是存储在堆中可能会对执行的转换顺序产生影响,但对其中一种或其他情况采取任何保证都是不明智的。

正如另一个答案所说,NaN总是保证不同的。这是IEEE-754浮点标准的定义。C和Java都将其用于浮点和双位表示,因此将NaN视为不同的。

a=Double.NaN;
b=a;
if (a==b)   // <--- comparison will fail.

但是对于所有其他值,该比较将根据该值的IEEE-754比特模式来表现。如果两个变量的位表示相同,则该比较将产生true。

因此,对于您使用randdouble()的示例,您对a==b的比较将始终为true,因为您从a中实际复制了位表示形式以用于b的赋值(假设randdouble)永远不会返回NaN)。

话虽如此。。。您永远不应该依赖于代码中浮点值的精确比较。在我们这里的琐碎示例中,通过彼此直接赋值来获得比较值是非常罕见的。它们通常是通过一些计算得出的。比较的每一面往往是通过一系列不同的计算得出的。由于IEEE-754限制所固有的累积误差,计算常常在比特表示中产生略微不同的结果。

因此,内存位置也无关紧要,因为无论存储在哪里,位模式都是相同的。

这在C或Java(或任何其他使用IEEE-754浮点表示的语言)之间也无关紧要。

相关内容

  • 没有找到相关文章

最新更新