2016-07-29 67 views
2

我知道比较两个doubles有问题,如果它们是从不同的计算中获得的。但是,如果其中一个是另一个的副本(价值),这是否也适用。以下几行解释了这种情况。如果我有这样的)问题,比较float和它的副本

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

然后,

Q1是比较a==b始终保证在C编译器的情况下返回true(我有gcc 6.1.1)? Q2)如果我使用malloc在堆内存中分配变量ab,那么上述答案是否保持不变?

Q3)请问上述答案仍然是相同的,如果我有一个Java编译器(我使用Open JDK 1.7.0)与ofcourse必要的语法改变取代C编译器。

编辑1:数字ab!= NaN

+0

1)否,2)是,3)是 –

+0

@EugeneSh。为什么'b = a'不会导致'b == a'成立。这是内存或寄存器的直接副本。 –

+0

@JoshSanford问题是关于*保证*。 –

回答

3

Q1:比较不保证评估为true,原因很简单,那NaN比较不等于本身。也可能有其他情况,但NaN是一个明显的反例。第二季度:变量驻留在内存中没有什么不同。

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

这种特殊情况之外,我认为标准没有作出这样的保证:

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

+0

我正在对'NaN'的存在进行故障安全检查。我会更新关于'NaN'不存在的问题。你能相应地更新你的答案吗? – Abhinav

+0

您所做的检查不会改变事实。 –

+0

@EugeneSh。那个怎么样? 'pseudoRandom'生成器能产生一个'NaN'吗? – Abhinav

2

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

a=Double.NaN; 
b=a; 

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

但是对于比较将根据该值的IEEE-754位模式表现的所有其他值。如果两个变量的比特表示是相同的,那么比较结果就会成立。

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

这就是说......你不应该依赖代码中浮点值的精确比较。你的比较值很难通过直接分配来得到,就像我们这里的小例子那样。他们通常是通过一些计算得出的。比较的每一方通常都是通过一系列不同的计算得出的。由于IEEE-754限制固有的累积误差,计算结果在位表示中经常会产生稍微不同的结果。

因此,无论存储位置如何,存储器位置都不重要,因为位模式是相同的。在C或Java(或使用IEEE-754浮点表示的任何其他语言)之间,它也不会有问题。

+1

是否保证赋值运算符正在产生精确的位拷贝?是否保证比较操作总是返回true,以防精确位副本(带有NaN异常)?我不这么认为,但会寻找参考。 –

+0

@EugeneSh。我认为这是我困境的症结所在。赋值运算符是否产生精确的位拷贝。 – Abhinav

+0

我认为你不应该依赖这个。如果你真的想做一个对象的确切副本并逐位比较,使用'memcpy'和'memcmp'。我可能在这里错了,虽然,因为我没有找到很好的参考。 –