PDA

View Full Version : Bug disappears when debugging



Yes
7th May 2012, 13:54
Hi!

I'm having a bug in an application I'm developing with Qt Creator. However, when I press F5 to try to debug the application, the bug mystically disappears. Why does it do that? I can just think of two things that could cause this behavior:

1. The compiler makes some bad optimization when compiling the application in release mode, which causes a bug, or

2. Some constants defined by the compiler, which I'm accidentally using, change values. I have a file which in my project which is included in all other source and header files. In that file I have defined a flag called DEBUG, but all that happens if this is set to 1 is that it conditionally throws some exceptions on different places in the code. If an exception is thrown, the program always exits, but it doesn't exit so no exception is thrown.

I would really appreciate if I could get some help with this problem, thanks in advance.

Edit: Okay, I have located the bug. This is really strange. I have the code



float A = 0;
float B = C * A;
if (A) {
throw logic_error("A is non-zero");
}
if (B) {
throw logic_error("B is non-zero");
}


where C if a float that is calculated since before. A is zero so B should become zero, but I still get the message "B is non-zero" from a try-catch clause that encapsulates the code. How is this even possible? When I press F5 to debug the application this doesn't occur.

mvuori
7th May 2012, 15:10
I think the lesson here is that one should never trust floating point numbers to be exactly anything, not even zero...

You should do the check this way: if (abs(X) < 0.00000001) {...}

This is silly, of course, but that's the way of floats.

Yes
7th May 2012, 15:36
I don't think that a multiplication between two real floats will always zero if one of them are zero. To me it seems a bit arbitrary to just pick a constant 0.00000001 to compare the result with.

However, I printed C and B to stdout (which I should had done immediately) and C was nan (not a number) which is not a real number, hence, B also became nan. It's strange that this only happens in release mode and not in debug mode, though.

Thanks anyway for your reply.

d_stranz
7th May 2012, 21:10
Contrary to what mvuori says, I think it is always safe to compare a floating point zero to 0.0. The binary representation of zero is exact no mater what numerical type it is.

If this is all there is to your code, then there is nothing wrong with it. My guess is that somewhere after C is defined but before the multiplication occurs, you have corrupted memory or you are dividing C by something that has not been initialized or is zero.

Compilers generate different code in debug vs. release mode - typically, in debug mode, all pointers are initialized to some impossible value (but the same one), numbers are initialized to something else. This is to help you find problems with initialization. In release mode, everything is random - there's no initialization. Whatever the memory occupied by your variables is set to before the program starts, that's what it is set to after it starts. So the behavior you are seeing is "normal" and what you should expect when there is an initialization problem. The solution is to look at every variable that is used in computing the value of "C" and make sure it is being initialized to something meaningful before it is used.

Yes
7th May 2012, 23:10
Hm, Okay, that seems like a reasonable explanation. I didn't actually know that pointers and numbers were usually initialized in debug mode. I haven't had time to debug the code since I wrote my last post, but I'm sure I will be able t track it down quickly now that I know the problem is that C is nan.

And thank you mvuori, even though your suggestion wasn't the correct reason, it helped me to realize I should find out what values are contained in all other variables than A used to calculate B, which gave me the answer to my question.

ChrisW67
7th May 2012, 23:58
Contrary to what mvuori says, I think it is always safe to compare a floating point zero to 0.0. The binary representation of zero is exact no mater what numerical type it is.

If you have explicitly set a float/double to 0.0 or -0.0* then an explicit or implicit comparison to 0.0 will be true. If you have computed the value you are comparing to zero then you must be careful. Answers that should be precisely zero (in an ideal world) may not be.



float a = 29.0;
float b = 2.9;
float c = (a / 10.0) - b;
qDebug() << a << b << c << (c == 0.0);
// 29 2.9 -9.53674e-08 false


* 0.0 and -0.0 are both allowable values and both compare equal to 0.0 but they they do have different binary representations and different behaviours under some circumstances.


union test_union {
float f;
quint32 i;
};

test_union x;
x.f = 0.0;
qDebug() << QString::number(x.i, 16);
// "0"
x.f = -0.0;
qDebug() << QString::number(x.i, 16);
// "80000000"

Yes
8th May 2012, 00:06
Good to know if you are going to reinterpret a float as an integer. I just read a couple of days ago about a square root algorithm that did just that in order to come up with a good initial guess for the iterative method they used.

And yes, I would never trust that a floating point calculation is exactly what you expect it to be, unless you have made a numerical error estimation that shows that the truncation error will be absolutely zero (like in my case, if just the other number would have been a real number).

d_stranz
8th May 2012, 21:05
If you have explicitly set a float/double to 0.0 or -0.0* then an explicit or implicit comparison to 0.0 will be true.

But I would expect this result, which is essentially what was in the original post:


float a = 0.0;
float b = 2.9;
float c = a * b;
qDebug() << a << b << c << (c == 0.0);
// 0 2.9 0 true

Could there be a case when multiplication by a variable initialized to zero could yield a result that compares as non-zero?

ChrisW67
8th May 2012, 22:49
Could there be a case when multiplication by a variable initialized to zero could yield a result that compares as non-zero?
Sure. Any expression containing a NaN results in NaN, even multiplying by 0.0. NaN is not equal to anything else so the result does not equal 0.0.



#include <QDebug>
#include <limits>

int main(int argc, char **argv)
{
// Simulate a variable arriving as NaN from a previous erroneous computation
// Clearly you would not do this deliberately
float a = std::numeric_limits<float>::quiet_NaN();

// then multiply it by zero
float b = 0.0;
float c = a * b;
qDebug() << c << (c == 0);
}

Yes
8th May 2012, 23:53
NaN is not equal to anything else so the result does not equal 0.0.

NaN isn't even equal to itself, according to the IEEE floating point standard. Therefore, to check if a number is NaN, you can compare it to itself and see if the result of the comparison is false or not. Just beware, some high optimization levels are documented to break IEEE standards and may optimize the comparison to always result in true.