两个双打是否可以相等而不是同时相等?

Mar*_*dik 4 c++ floating-point

我的程序中有一个非常奇怪的错误.我无法在可重现的代码中隔离错误,但在我的代码中的某个位置有:

    double distance, criticalDistance;
    ...

    if (distance > criticalDistance)
    {
        std::cout << "first branch" << std::endl;
    }
    if (distance == criticalDistance)
    {
        std::cout << "second branch" << std::endl;
    }
Run Code Online (Sandbox Code Playgroud)

在调试构建中一切都很好.只执行一个分支.

但是在发布版本中,所有地狱都会破裂,有时两个分支都会被执行.

这很奇怪,因为如果我添加else条件:

    if (distance > criticalDistance)
    {
        std::cout << "first branch" << std::endl;
    }
    else if (distance == criticalDistance)
    {
        std::cout << "second branch" << std::endl;
    }
Run Code Online (Sandbox Code Playgroud)

这不会发生.

请问,这可能是什么原因?我在32位计算机上的Ubuntu 13.10上使用gcc 4.8.1.

EDIT1:

我正在使用预编译器标志

  • -std = GNU ++ 11
  • -gdwarf-3

EDIT2:

我不认为这是由内存泄漏引起的.我用valgrind内存分析器分析了发布和调试版本,跟踪了单元化内存并检测了自修改代码,我发现没有错误.

EDIT3:

将声明更改为

volatile double distance, criticalDistance;
Run Code Online (Sandbox Code Playgroud)

使问题消失.这是否证实了woolstar的答案?这是编译器错误吗?

EDIT4:

使用gcc选项-ffloat-store也可以解决问题.如果我理解正确,这是由gcc引起的.

woo*_*tar 14

if (distance > criticalDistance)
  // true
if (distance == criticalDistance)
  // also true
Run Code Online (Sandbox Code Playgroud)

我之前在自己的代码中看到过这种行为.这是由于存储在内存中的标准64位值与英特尔处理器用于浮点计算的80位内部值不匹配.

基本上,当截断为64位时,您的值相等,但在以80位值测试时,一个稍大于另一个.在DEBUG模式下,值始终存储在内存中,然后重新加载,因此它们总是被截断.在优化模式下,编译器会重用浮点寄存器中的值,并且不会被截断.

  • @EricPostpischil虽然标准需要适当的行为,但我实际上已经在我自己的代码中的`gcc`编译器中准确地追踪了这个问题.所以在**练习**中,`gcc`就是这样做的,无论**理论中应该发生什么**. (3认同)
  • 这不应该发生.C和C++标准要求,在执行赋值时,将值转换为其实际标称类型; 必须丢弃过高的精度.因此,'distance`和`criticalDistance`的使用在两个表达式中应该完全相同.如果涉及复合表达式,例如`distance> r*r`和`distance == r*r`,过多的精度可以解释行为,这将允许在两个实例中以不同方式计算`r*r`. (2认同)
  • @JoopEggen:我们知道当使用不同的精度时会出现差异.问题在于C++标准禁止在问题中显示的情况下使用过多的精度,并且GCC C++实现违反了标准. (2认同)