tags:

views:

56

answers:

5

I tried following code snippet and output is surprising me:

#include <stdio.h>
#include <math.h>

int main()
{
            double num;
            unsigned char ch;

            ch = 19;
            num = 1.0E+20 ;
            num += ch * 1.0E+18;
            printf("E18 = %lf \n",num);
            printf("E18 = %e \n",num);

            num = 11.0E+21 ;
            num += ch * 1.0E+19;
            printf("E19 = %lf <------\n",num);
            printf("E19 = %e <------\n",num);

            num = 11.0E+22 ;
            num += ch * 1.0E+20;
            printf("E20 = %lf\n",num);
            printf("E20 = %e\n",num);

            num = 11.0E+23 ;
            num += ch * 1.0E+21;
            printf("E21 = %lf\n",num);
            printf("E21 = %e\n",num);

            num = 11.0E+24 ;
            num += ch * 1.0E+22;
            printf("E22 = %lf <------\n",num);
            printf("E22 = %e <------\n",num);
    return 0;
}

The output of the program:

E18 = 119000000000000000000.000000 
E18 = 1.190000e+20 
E19 = 11190000000000000524288.000000 <------
E19 = 1.119000e+22 <------
E20 = 111900000000000001048576.000000
E20 = 1.119000e+23
E21 = 1119000000000000044040192.000000
E21 = 1.119000e+24
E22 = 11189999999999999366660096.000000 <------
E22 = 1.119000e+25 <------

Why the data corrupted when printed while in exponent form its OK

+5  A: 

Because, you lose precision when the numbers grow big enough : http://en.wikipedia.org/wiki/Floating_point

Tuomas Pelkonen
Or even small enough.
Vulcan Eager
A: 

Double/floating-point numbers lose precision as they get larger - in addition to the Wikipedia article Tuomas has posted, here's another good one:

http://www.yoda.arachsys.com/csharp/floatingpoint.html

It was targeted at .NET but the principle still applies.

Andy Shellam
+2  A: 

The data is not corrupted; that's simply how floating point values work in today's computers. Think of a float as a fixed number of digits (the mantissa) and another number that indicates where the decimal point should be placed (the exponent). For the long and more accurate story, Wikipedia is a good start.

Since the number of digits of the mantissa is fixed, it cannot represent the tiny fraction that you're asking for here. Furthermore, because it's all in binary, decimal numbers cannot always be represented exactly.

The exponential notation simply rounds off the last few digits where the number is known to be inaccurate, hence your results.

Thomas
A: 

Floating point data types use a finite number of bits to represent a certain range of numbers. However, there can be an infinite number of values between any two real numbers m and n. So, you sacrifice precision.

It looks alright in exponent form since not all digits are being printed.

As a test, try printing the value 0.2 with about 10 decimal places and you will see that the value stored is more like 0.1999999....

Vulcan Eager
A: 

You are seeing the imprecision inherent in floating point.

Certain printf conversions are guaranteed to produce enough significant figures to uniquely identify the number being printed. This implies that if there is any imprecision, you will see it. Conversely, the default %e/%f representation hides the imprecision by rounding.

As far as I know, %a (hexadecimal floating point) is the only way to achieve this. According to the POSIX spec, %lf is defined to do the same thing as %f, that is,

l (ell) … has no effect on a following a , A , e , E , f , F , g , or G conversion specifier.

So this is technically a bug in your standard library.

Potatoswatter