Thursday, February 18, 2016

Why it's bad to use floting point numbers for equality or condition checking ?




Most of the suggestions are to avoid floating-point numbers from equality checking or in condition checking. Because small errors in the rightmost decimal places are likely to arise when calculations are performed on floating-point numbers, And two float or double values (float and double are also different) rarely are exactly equal.

assume ,

double oneThird = 1.0 / 3.0;
double x = oneThird + oneThird + oneThird;

actually expected result is x to be equal to 1. But it probably doesn't. Because the first assignment statement stores an approximation of 1/3 in to oneThird, which is likely to be 0.3333333 (But actually it's 0.33333.....)
So the second statement stores something like 0.9999999 in to x.
So the computer will compare x with 1 and it recognize it as a mismatch. so eventually it will yield false.

Some interesting code snippets are listed below.

double a = 0.9999999999999999999;
if (1 == a) {
    System.out.println("1 equals to 0.9999999999999999999");
} else {
    System.out.println("1 does not equals to 0.9999999999999999999");
}
// prints "1 equals to 0.9999999999999999999"
float x = 1.1f;
double y = 1.1;
if (x != y) {
    System.out.println("1.1f and 1.1 does not match");
}
// prints "1.1f and 1.1 does not match"
double oneThird = 1.0 / 3.0;
double one = oneThird + oneThird + oneThird;
if(1.0000000000000000001 == one){
    System.out.println("1.0000000000000000001 equals to one");
} else {
    System.out.println("1.0000000000000000001 does not equals to one");
}
// prints "1.0000000000000000001 equals to one"
double a1 = 1.0/3.0;
double a2 = 0.333333;
if(a1 == a2){
    // programmer might think this will be the case !!!
    System.out.println("1.0/3.0 is equal to 0.33333");
}else{
    System.out.println("1.0/3.0 is not equal to 0.33333");
}
// prints "1.0/3.0 is not equal to 0.33333"
So how can we avoid this. Instead of checking for equality, we can test for near equality. one famous way to do this is to compute the difference between the numbers and see whether the result is less than some maximum allowable difference.
double EPSILON = 1.0e-7;
if (Math.abs(1 - a) < EPSILON) {
    System.out.println("yes");
} else {
    System.out.println("no");
}
// prints "yes"
Some interesting articles about this area are listed below.
0.999...
Why do so many people reject proofs that 0.999999... = 1?
Relational operators with floating point types
What Every Computer Scientist Should Know About Floating-Point Arithmetic ?
Comparing floating point numbers
Comparing Floating Point Numbers - by Random ASCII
Doubles are not floats, so don’t compare them
Why not use Double or Float to represent currency?

0 comments:

Post a Comment