Difference between two doubles is wrong (C++)

difDoubles.cpp

The questions may be like this: Be aware of precision issues when handling doubles. Never try to check two floating point variables for equality..
Let’s have a look at the problematic code.

#include <iostream>

using namespace std;

int main()
{
    double epsilon=0.001;
    double d1=2.334;
    double d2=2.335;
 
    cout<<"epsilon is: "<<epsilon<<endl;
    cout<<"d2-d1 is: "<<d2-d1<<endl;
 
    if ((d2-d1)==epsilon)
        cout<<"Equal!";
    else
        cout<<"Not equal!";
    return 0;
}

which outputs

epsilon is: 0.001
d2-d1 is: 0.001
Not equal!

In order to understand why this code provides not the result the programmer expected, we should take a look at this code.

#include <iostream>
#include <iomanip>
using namespace std;
int main()
{
    double epsilon=0.001;
    double d1=2.334;
    double d2=2.335;
  
    cout<<"epsilon is: "<< setprecision(20) << epsilon<<endl;
    cout<<"d2-d1   is: "<< setprecision(20) << d2-d1 <<endl;
  
    if ((d2-d1)==epsilon)
        cout<<"Equal!";
    else
        cout<<"Not equal!";
}

which outputs

epsilon is: 0.0010000000000000000208
d2-d1   is: 0.00099999999999988986588
Not equal!

Take home message: Never try to check two floating point variables for equality.

In order to bypass this behavior, we are using an approximation error like this

if(abs(d2-d1)<epsilon)

or this

if(fabs(d2-d1) <= epsilon * fabs(d2))

which requires the library. This will provide the desired result. For more, click here.

The important rule to remember is that powers of two and integer multiples thereof can be perfectly represented. everything else is an approximation.
For example, 1.5 can be represented perfectly, because it is 3 * 2-1.
However, 3.6 cannot be exactly represented, because it is not an integer multiple of a power of 2.
You can use this link to see what the actual binary representation of your floating point value will be.

Interesting code by Soma

#include <iomanip>
#include <iostream>
 
const double kTarget(1.00048828125); // These values are subject to potentially greater errors
const double kEpsilon(0.00048828125); // thanks to multiple operations when not accurately represented.
 
double Update
(
    const double fValue
  , const unsigned int fMultiple
)
{
    double sResult(fValue);
    for(unsigned int cMultiple(1); fMultiple > cMultiple; ++cMultiple)
    {
        sResult += fValue;
    }
    //sResult *= 1.25; // You may alternate between values which can be
    sResult *= 1.26;   // accurately represented and approximated values.
    return(sResult);
}
 
int main()
{
    using namespace std;
    cout << fixed;
    for(unsigned int cMultiple(0); 10 > cMultiple; ++cMultiple)
    {
        double sValue1(Update(kTarget, cMultiple));
        double sDifference(Update(kEpsilon, cMultiple));
        double sValue2(sValue1 + sDifference);
        if((sValue2 - sValue1) != sDifference)
        {
            cout
                << "Bad Result: "
                << setprecision(16) << sValue1 << " : "
                << setprecision(16) << sValue2 << " : "
                << setprecision(16) << sDifference << '\n'
            ;
        }
    }
    return 0;
}

Have questions about this code? Comments? Did you find a bug? Let me know!😀
Page created by G. (George) Samaras (DIT)

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s