views:

99

answers:

3

Which is the better way(efficiency/best practice wise) to test if a double variable is equal to 0?

    1. if(a_double)
          .....
       else
          .....

    OR

    2. if(a_double == 0)
          .....
       else
          .....
+6  A: 

The second is generally better (more explicit about what you're doing). I'd normally prefer if (a_double == 0.0) though. Also note that with floating point, it's often useful to do an approximate comparison to account for the possibility of rounding in the calculations (though doing this well can be non-trivial).

Edit: Since there appears to be some misunderstanding about what numbers can and can't be represented precisely: most computers use binary floating point. This means a fraction in which the denominator is a sum of powers of two can be represented exactly. If (and only if) the denominator contains a prime factor that cannot be represented as a sum of powers of 2 is it impossible to represent that number precisely.

Of course, if you get too small (or too large) it can be impossible to represent the number at all (e.g., normal IEEE floating point doesn't provide a way to represent a number like 1e+10000 or 1e-2000). Also, when you approach the limits of representation, you give up some precision (e.g., the limit for a normal double is 1e-308 -- and at 1e-300, you only get ~7 digits of precision instead of the usual ~15).

Within certainly limits, however, integers can be represented precisely (depends on the size of the significand -- usually around 253), and so can fractions where the denominator is a sum or powers of 2 (e.g., 3.5, 1.375).

There are also computers that use hexadecimal floating point and/or decimal floating point. For what we're considering here, hexadecimal floating point is essentially the same as binary floating point (i.e., since 16 is a power of 2, it can still only represent fractions precisely if the denominator is a sum of powers of 2). Decimal floating point allows precise representation of numbers where the denominator includes powers of 5 as well (e.g., 1.2 can be represented precisely in decimal floating point but not in binary or hexadecimal floating point). This has the obvious advantage that (again, within the limits of its range and precision) anything you enter as a decimal number will be represented precisely.

Jerry Coffin
*...often useful to do an approximate comparison...*
pst
Thanks Jerry. How comparing a_double to 0 is different from 0.0?
who am i
The first one requires a compile-time conversion from integer to double, the second already is a double.
Ben Voigt
got it, thanks Ben.
who am i
Ok, I understand denormalized representation (used for very small values) loses precision, but why does 1e300 have reduced precision?
Ben Voigt
@Ben: Oops -- a stupid thinko there -- put in `+300` and `+308` where I'd intended `-300` and `-308`. My apologies.
Jerry Coffin
+2  A: 

Because in general doubles are not going to be exactly equal to any integer you need to be careful when testing them for equality.

Read this: http://docs.sun.com/source/806-3568/ncg_goldberg.html

In essence with a float you want to test that the float is close to some number within some tolerance.

shuttle87
Your first statement is somewhat misleading because some doubles *do* exactly equal a corresponding integer.
Greg Hewgill
Excellent reference, although it's not really true to say that "doubles are not going to be exactly equal to any integer". Plenty of integers (including 0 :-)) are exactly representable as a floating-point number.
David Gelhar
But even if the number is representable in a floating-point format, what your double actually stores might be different due to rounding errors in its computation. Most likely, he didn't just assign 0.0 to the double (since that'd make the comparison pretty pointless). If he made some computation, and is checking the result against 0, then @shuttle87 is absolutely correct: *in general* you can't rely on it to reach the exact right result, even if the desired result can be represented as FP.
jalf
A: 

Edit

Apologies for the previous incomplete and incorrect explanation. This is what I meant.

#include<iostream>
using namespace std;
int main(){
double a=3/5;
double b=2/5;
double c=(a+b)-1;
if(c==0)
        cout<<"C is 0"<<endl;
else if(c==0.0)
        cout<<"C is 0.0"<<endl;
else
        cout<<"C!=0 && C!=0.0"<<endl; //This will print most of the time
}

--Edit Ends--

You may have to read the test cases as to how a_double gets its values. The greatest problem as @Jerry told is that it's difficult to test == with double. Note the following will not work as expected..

#include<iostream>
using namespace std;
int main(){
double a=5.5;
double b=6.5;
double c=(a+b)/12;
if(c==0)
        cout<<c<<endl;
else
        cout<<"c is not equal to 0"<<endl;
}
will not work OR may not work?
Chubsdad
uh, c==1 here...
David Gelhar
There appears to be some confusion about what 12 divided by 12 is. However I feel confident that it won't be zero.
Ben Voigt
@Greg: What's important is that 11/2 and 13/2 are exactly representable. For example, 10000000000.5 is not representable even though the denominator is a power of 2.
Ben Voigt