Link to home
Start Free TrialLog in
Avatar of BrunoFLopes
BrunoFLopes

asked on

Float / double precision


Hi ...

I'm having problems dealing with floating point numbers in C.

The app we're developing requires great precision (sometimes to the 20th decimal point).

Problem is:

When I do this:

      double abc;
      abc = 8080.9940;
      printf("Value: %.30lf\n", abc);

I get in the output:

         Value: 8080.993999999999700000000000000000

When I was expecting:

        Value: 8080.994000000000000000000000000000

Why this happens ? How can I avoid it ?

Thanks!

Bruno Monteiro Lopes
IST - Lx, Portugal
Avatar of Kent Olsen
Kent Olsen
Flag of United States of America image

Hi BrunoFLopes,

Floating point arithmetic isn't an "exact science" and you're seeing some of the effects of this.

One of two things is happening.  The compiler is generating the value 8080.9940 by calculating it via 80809940/10000, or the conversion to ASCII is losing precision.

When I run the following test program, I get the same value that you do.  However, the second line shows a pretty normal looking bit string.  This suggests that the C library is losing precision when the value is converted for display.




#include <stdlib.h>
#include <stdio.h>

typedef union
{
  double DV;
  long   IV;
} DI;

DI X;

int main()
{
     X.DV = (double)8080.9940;
     printf("Value: %.30lf\n", X.DV);
     printf("Value: %16X\n", X.IV);
     getchar ();
     return 0;
}



Good Luck,
Kent
Hi
The solution is BCD arithmetic where numbers are represented by strings.

Marek
Hi BrunoFLopes,


You avoid that problem if you leave it to the compiler how many decimals to display ("%f"). With your format you are forcing a certain number of decimals and depending on the implementation you will see diffrent values (my AIX xlc gives me 8080.993999999999687133822590110000 ).
BTW: why do you use the 'l' type? That's for long int types only.



======
Werner
ASKER CERTIFIED SOLUTION
Avatar of stefan73
stefan73
Flag of Germany image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
A free library developed by an open source group is available, which deals with very large numbers and high precision arithmetic. This has been developed for the work related to cryptography.
Using their APIs you can do ANY precision arithmetic with floating point numbers.
Here are the urls:
http://swox.com/gmp/
ftp://ftp.gnu.org/gnu/gmp

-ssnkumar
BTW: Think about using C++ for this task, since you'll have all operators defined exactly in the way you'd expect them to be.

That's a bit messy with a C lib.
Avatar of grg99
grg99

You're asking printf to display 30 decimal places.

a double is probably 64 bits, with maybe 48 bits of precision.
48 bits is about 15 decimal digits.
Your number has 4 digits to the left of the decimal point, so you can expect about 11 digits to the right.

If you print out the number with %4.11lf format, then printf will round the number to the expected value.

By the way, you may want to re-think why you need 20 digits of precision-- there are darned few programs that really need this for a good reason.

Floating point numbers are represented as a mantissa and an exponent (which defines the position of the floating (decimal) point.  The mantissa in turn is represented as a power of 2 (not a power of 10) as a consequence, some round decimal numbers will become repeating binimals.  Consider 1b3/10b3 = 0.1b3 but 0.333...b10.  I'd show you 1/10 -> b2 but my good calclulator is home and trying to do it on paper is making my head hurt.
As an aside, are you sure that you are approaching your problem the best way?  In distance terms, you are talking about better than +/- 1 millimeter/light year.  
BrunoFLopes,
Here is a good link which demonstrates the power (or weaknesses) of IEEE-754 floating points:
http://babbage.cs.qc.edu/courses/cs341/IEEE-754.html

Stefan