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 formulasit 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.