C - Summation with Double - Precision

2019-06-14 19:18发布

问题:

I have problem with precision of double format.


Sample example:

double K=0, L=0, M=0;
scanf("%lf %lf %lf", &K, &L, &M);
if((K+L) <= M) printf("Incorrect input");
else printf("Right, K=%f, L=%f, M=%f", K, L, M);

My test input:

K = 0.1, L = 0.2, M = 0.3 -> Condition but goes to 'else' statement.


How I can correct this difference? Is there any other method to summation?

回答1:

In the world of Double Precision IEEE 754 binary floating-point format (the ones used on Intel and other processors) 0.1 + 0.2 == 0.30000000000000004 :-) And 0.30000000000000004 != 0.3 (and note that in the marvelous world of doubles, 0.1, 0.2 and 0.3 don't exist as "exact" quantities. There are some double numbers that are very near them, but if you printed them with full precision, they wouldn't be 0.1, 0.2 and 0.3)

To laugh a little, try this: http://pages.cs.wisc.edu/~rkennedy/exact-float

Insert a decimal number and look at the second and third row, it shows how the number is really represented in memory. It's for Delphi, but Double and Single are the same for Delphi and for probably all the C compilers for Intel processors (they are called double and float in C)

And if you want to try for yourself, look at this http://ideone.com/WEL7h

#include <stdio.h>

int main()
{
    double d1 = (0.1 + 0.2);
    double d2 = 0.3;

    printf("%.20e\n%.20e", d1, d2);

    return 0;
}

output:
3.00000000000000044409e-01
2.99999999999999988898e-01

(be aware that the output is compiler dependant. Depending on the options, 0.1 + 0.2 could be compiled and rounded to 0.3)



回答2:

Unlike integer values floating point values are not stored exactly the way you assign values to them. Lets consider the following code:

int i = 1; // this is and always will be 1
float j = 0.03 // this gets stored at least on my machine as something like 0.029999999

Why is this so? Well how many floating point number exist in the interval between 0.1 and 0.2? An infinite number! So there are values which will get stored as you intended but a hell of a lot of values which will be stored with a small error.

This is the reason why comparing floating point values for equality is not a good idea. Try something like this instead:

float a = 0.3f;
float b = 0.301f;
float threshold = 1e-6;

if( abs(a-b) < threshold )
  return true;
else
  return false;


回答3:

There are infinitely many real numbers between any two distinct real numbers. If we were to be able to represent every one of those, we would need infinite memory. Since we only have finite memory, floating point numbers need to be stored with only finite precision. Up to that finite precision, it might be not be true that 0.1 + 0.2 <= 0.3.

Now, you really should go read what's at the other end of the excellent link provided by Paul R.