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.993999999999700000000
When I was expecting:
Value: 8080.994000000000000000000
Why this happens ? How can I avoid it ?
Thanks!
Bruno Monteiro Lopes
IST - Lx, Portugal
Hi
The solution is BCD arithmetic where numbers are represented by strings.
Marek
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.993999999999687133822 590110000 ).
BTW: why do you use the 'l' type? That's for long int types only.
======
Werner
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.993999999999687133822
BTW: why do you use the 'l' type? That's for long int types only.
======
Werner
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
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
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.
That's a bit messy with a C lib.
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.
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
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
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