Login | Register   
RSS Feed
Download our iPhone app
Browse DevX
Sign up for e-mail newsletters from DevX


Detecting the Properties and Limits of Numeric Datatypes -2 : Page 2

Floating Point Blues
C++ floating point datatypes have finite precision. Hardware-specific vagaries contribute their own share to the truncation and rounding of floating point datatypes. Now you understand why the result of the expression 2.0/3.0 is approximated as 0.66666666666666663 on my machine. This "digital noise" is a fertile source of many bugs. Consider:

double d1=2., d2=3.; d1/=d2; // 2/3 if (d1*10==(20./d2)) //condition should be true, alas { //unreachable code do_equal(); }

The code between the pair of braces is never executed because the subexpressions on both sides of the == operator yield slightly different results: d1*10 is 6.6666666666666661 whereas 20./d2 is 6.6666666666666670. The difference between these two numbers is an artifact of the truncation and approximation incurred by floating point arithmetic. As a workaround, you can replace floating point datatypes with scaled integers. Sometimes however, this isn't an option. Consider a spreadsheet that evaluates complex formulas—it must use floating point types. For such cases, the epsilon constant comes in handy. Epsilon is the difference between 1 and the smallest value greater than 1 that is representable for a given datatype. For example, the epsilon value for type double is:

#include <iostream> #include <limits> using namespace std; cout << numeric_limits<double>::epsilon( ) << endl; //output: 2.22045e-016

To neutralize the effect of digital noise in the if-statement, replace the == operator with an expression that checks whether the two values are roughly identical:

if ( ((d1*10)-(20.0/d2)) <= numeric_limits<double>::epsilon()) { do_equal(); }

If the result of the expression (d1*10)-(20.0/d2) isn't higher than the epsilon for type double, it's practically zero. Hence, the two subexpressions have identical values. Using this technique you can fine-tune the error threshold. For example, if a difference of one billionth or less is insignificant in your application, try the following:

const double BILLIONTH=1./1000000000; if ( ((d1*10)-(20.0/d2)) <= BILLIONTH)

Remember though that epsilon is always the lowest deviation threshold.

Comment and Contribute






(Maximum characters: 1200). You have 1200 characters left.