tags:

views:

149

answers:

5

I just ran into this line of code;

if( lineDirection.length2() ){...}

where length2 returns a double. It kind of puzzles me that 0.0 in this case is equivalent to 0\NULL.

Is this part of the C++ standard or is it undefined behaviour?

+4  A: 

Yes - the comparison is against zero (0.0), and returns false if the result is exactly zero, and true otherwise.

The behaviour is inherited from C, which treats the equivalent comparison the same way.

Jonathan Leffler
A: 

When you compare without operators, you are comparing "against true", so that every variable type is checked to be either boolean (simple case) or other. Numeric variable types has their false value defined as "0", "0.0" or so, so when you compare them "against true", your comparison will return false.

Tomasz Kowalczyk
+5  A: 

It's worth noting that this code is extremely brittle for floating-point representations. This code will work if and only if the floating point value is exactly 0, which is actually pretty unlikely in most circumstances. It may not be in this particular case, but it should certainly be documented / commented if so.

In practically all other situations you need to decide on an "epsilon value" that defines the range of floating point numbers you consider "the same" - otherwise your comparisons are very likely to surprise you in corner (and often not-so-corner) cases.

MadKeithV
+1 for pointing out the brittleness of the code. This will break in many conditions that may not be obvious: `double d = 0.0 / -1.0; if (d)` yields false, as `-0.0 != 0.0`, and the same goes for many other operations that may yield a close enough to `0` value that is not **exactly** `0.0`
David Rodríguez - dribeas
Just to be sure. Could the code "double x=0.0;if(x){cout << "x is not null";} " print "x is not null" ?
Benoît
@David Rodríguez - dribeas: No, `-0.0 == 0.0`, even if the bit patterns would differ. This is critically important. The expression `(x==0.0 || (1.0/x))` will _not_ evaluate `1.0/x` when that would cause a division by zero.
MSalters
@Benoît: Since that is a compile time constant, chances are that the compiler will inject a real `0.0` there. The problem comes when there is any arithmetic operation, and that is because exact comparison of floating point numbers is hard will fail in many situations. Read this article: http://docs.sun.com/source/806-3568/ncg_goldberg.html
David Rodríguez - dribeas
@MSalters: The exact code I have posted has been tested with g++ 4.2/4.5. The code you posted causes a division by `-0.0` and the result is `-inf`, again g++ 4.2/4.5 (MacOSX).
David Rodríguez - dribeas
@David Rodríguez - dribeas: can't we do if(int(d)==0){}? Is this safe?
Chubsdad
@David Rodríguez - dribeas: really surprising, since the GNU docs state the opposite. See http://www.gnu.org/s/libc/manual/html_node/Infinity-and-NaN.html (last line)
MSalters
@Chubsdad: You can do that, but the test is quite different as 0.9999 will be considered 0 after the conversion to int (and the same goes for -0.9999)
David Rodríguez - dribeas
+3  A: 

It is a very much Standard Behavior (Boolean Conversion)

$4.12/1 - "An rvalue of arithmetic, enumeration, pointer, or pointer to member type can be converted to an rvalue of type bool. A zero value, null pointer value, or null member pointer value is converted to false; any other value is converted to true."

Chubsdad
A: 

If length2 returns 0.0 it will be taken as false. But you might get surprising result with this comparison. Better use epsilon value as MadKeithV suggested during floating point comparison.

Liton