2014-01-28 193 views
2

我有下面的代码是展示一些非常奇怪的行为。有没有人有任何想法为什么。C++比较函数结果

#include <iostream> 

long global = 20001; 

double foo() {return global/1000.0;} 

int main(int,char**) { 
    if (foo() == foo()) { 
    std::cout << "true\n"; 
    } else { 
    std::cout << "false\n"; 
    } 

    return 0; 
} 

为函数返回相同的结果每次而是打印假这应该打印正确;

这是在Solaris 10上使用G ++ 我不知道该操作系统的事,但我还没有机会去尝试不同的OS

+0

试试这个: flost epsilon = 0.001f; if(foo() - foo()ε .... – AdamF

+1

我编译你的代码并收到'true'的响应。我使用gcc 4.6.3运行Ubuntu 12.04。它看起来像操作系统可能很重要。 – Kevin

+0

我在Fedora上用g ++得到'true' – Octopus

回答

3

操作系统可能并不重要,但是编译器和 架构做。在Intel上,通常的做法是在浮点寄存器中返回浮点数值 ,该浮点寄存器具有64位的精度(而不是双精度值的53)。当然,编译器会直接将该算术运算写入该寄存器中,因此您最终返回的值为64位,精度为 。

当然,当编译器生成的代码来调用一个函数, 它不能在寄存器中保留值,因为函数可能 使用该注册。所以它会让它记忆。作为双位与 56位。 ==运算符将第一次调用中的这个56位值与第二次调用中的64位值进行比较,发现他们不相等。

我可能会补充说,如果编译器内联函数,问题可能会消失。

根据标准,所有这些都是完全合法的。

+0

听起来很合理,有没有什么办法可以在不在本地存储变量的情况下进行比较工作?这是从一个更大的函数中获取的代码,其中将值存储在本地中并不是一个真正的选项 –

+1

-ffloat-store似乎通过防止寄存器上发生浮点比较来修复它。谢谢你,先生是个天才 –

1

有可能与双打不是评估一个问题建到始终完全相同的值(基本上舍入错误)。

如果你要改变你的函数返回整数,你可能会有预期的行为。

非常相似,这样的问题: Deals with comparing floats

试试这个:

#include <iostream> 
#include <limits> 

long global = 20001; 
double epsilon = std::numeric_limits::epsilon<double>(); 

double foo() {return global/1000.0;} 

int main(int,char**) { 
    if (foo() - foo() > epsilon) { 
    std::cout << "true\n"; 
    } else { 
    std::cout << "false\n"; 
    } 

    return 0; 
} 
+0

除了每次都会将_do_计算为相同的值。这个问题是英特尔在寄存器中扩展精度的一个副作用。 –

+0

啊。我不知道。所以这是一个唯一的问题? – Jmc

+1

今天,可能。在过去,我认为摩托罗拉芯片也使用了扩展精度,因此可能会显示相同的问题。 –