Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can two doubles be equal and not equal at the same time?

I have a very strange bug in my program. I was not able to isolate the error in a reproducible code but at a certain place in my code there is:

    double distance, criticalDistance;
    ...

    if (distance > criticalDistance)
    {
        std::cout << "first branch" << std::endl;
    }
    if (distance == criticalDistance)
    {
        std::cout << "second branch" << std::endl;
    }

In debug build everything is fine. Only one branch gets executed.

But in release build all hell breaks loose and sometimes both branches get executed.

This is very strange, since if I add the else conditional:

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

This does not happen.

Please, what can be the cause of this? I am using gcc 4.8.1 on Ubuntu 13.10 on a 32 bit computer.

EDIT1:

I am using precompiler flags

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

EDIT2:

I do not think this is caused by a memory leak. I analyzed both release and debug builds with valgrind memory analyzer with tracking of unitialized memory and detection of self-modifiyng code and I found no errors.

EDIT3:

Changing the declaration to

volatile double distance, criticalDistance;

makes the problem go away. Does this confirm woolstar's answer? Is this a compiler bug?

EDIT4:

using the gcc option -ffloat-store also fixes the problem. If I understand this correctly this is caused by gcc.

like image 419
Martin Drozdik Avatar asked Dec 03 '22 20:12

Martin Drozdik


1 Answers

if (distance > criticalDistance)
  // true
if (distance == criticalDistance)
  // also true

I have seen this behavior before in my own code. It is due to the mismatch between the standard 64 bit value stored in memory, and the 80 bit internal values that intel processors use for floating point calculation.

Basically, when truncated to 64 bits, your values are equal, but when tested at 80 bit values, one is slightly larger than the other. In DEBUG mode, the values are always stored to memory and then reloaded so they are always truncated. In optimized mode, the compiler reuses the value in the floating point register and it doesn't get truncated.

like image 98
woolstar Avatar answered Feb 15 '23 13:02

woolstar