比较浮点数及其副本

时间:2016-07-29 18:53:27

标签: java c comparison double malloc

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

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

然后,

Q1)对于C编译器(我有a==b),比较true是否始终保证返回gcc 6.1.1

Q2)如果我使用a在堆内存中分配变量bmalloc,上述答案是否会保持不变?

Q3)如果我用JAVA编译器替换C编译器(我正在使用Open JDK 1.7.0)并且必要的语法更改,那么上述答案是否会保持不变。

修改1:数字ab!= NaN

2 个答案:

答案 0 :(得分:3)

Q1:由于NaN比较不等于自身的简单原因,因此无法保证比较为真。可能还有其他情况,但NaN是一个明显的反例。

Q2:变量驻留在内存中没有区别。

问题3:我希望Java的行为类似。

除了这个特殊情况外,我确实认为标准没有给出这样的保证:

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

答案 1 :(得分:2)

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

a=Double.NaN;
b=a;

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

但对于所有其他值,比较将根据值的IEEE-754位模式运行。如果两个变量的位表示相同,那么该比较将产生真。

因此,对于使用randdouble()的示例,a == b的比较将始终为true,因为您从字面上将位表示复制到b的赋值中(假设randdouble()永远不会返回NaN)。 / p>

话虽如此......你不应该依赖于代码中浮点值的精确比较。很少见您的比较值是通过彼此直接分配得出的,就像我们这里的琐碎例子一样。它们通常是通过一些计算得出的。比较的每一侧通常通过不同的计算系列得出。由于IEEE-754限制所固有的累积误差,计算通常会在位表示中产生略微不同的结果。

因此,内存位置并不重要,因为无论位存储位置如何,位模式都是相同的。

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