10

I just ran into this line of code:

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

where length2 returns a double. It kind of puzzles me that 0.0 is equivalent to 0, NULL, and/or false.

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

mskfisher
  • 3,291
  • 4
  • 35
  • 48
Viktor Sehr
  • 12,825
  • 5
  • 58
  • 90

5 Answers5

10

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
  • 24,777
  • 4
  • 73
  • 129
6

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
  • 730,956
  • 141
  • 904
  • 1,278
6

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.

Community
  • 1
  • 1
Joris Timmermans
  • 10,814
  • 2
  • 49
  • 75
  • 3
    +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 Sep 22 '10 at 07:48
  • 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 Sep 22 '10 at 07:49
  • 6
    @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 Sep 22 '10 at 07:56
  • 1
    @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 Sep 22 '10 at 07:56
  • @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 Sep 22 '10 at 08:00
  • @David Rodríguez - dribeas: can't we do if(int(d)==0){}? Is this safe? – Chubsdad Sep 22 '10 at 08:01
  • 2
    @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 Sep 22 '10 at 08:06
  • @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 Sep 22 '10 at 08:08
0

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
  • 10,472
  • 6
  • 52
  • 68
0

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
  • 1,398
  • 2
  • 14
  • 27