0

I've been reading about the issues with floating point precision in C. I need 9 points of precision but as we can see this isn't working:

double d_lower = 0.123456789;
double d_upper = 123456789.0;
d_upper = d_upper + d_lower;
printf("d_upper: %.11f\n", d_upper);
// Outputs: d_upper: 123456789.12345679104
// Desired: 123456789.123456789

There are various posts about WHY this is happening on SO, such as these: Why Are Floating Point Numbers Inaccurate? Why can't decimal numbers be represented exactly in binary?

But I can't find any infomration on how to solve this problem? Is there a way to work around it? I need 9 points of accuracy, other people must have the same problem. Is it possible to make a union value that achieves this maybe?

My C skills are fairly basic so I can understand the problem but I can't see how to resolve it or work around it.

Community
  • 1
  • 1
jwbensley
  • 10,534
  • 19
  • 75
  • 93
  • 1
    In C, `double` specifies at least 10 decimal digits of _significance_. (most systems have 15+). If you want to maintain numbers like 1234567890123456789012345678901234567890.123456789, your code should use an arbitrary precision math library. I really think though, you are asking to solve the wrong sub-problem "need 9 points of precision". Suggest posting the higher level issue. [Printf width specifier to maintain precision of floating-point value](http://stackoverflow.com/q/16839658/2410359) may help. – chux - Reinstate Monica Sep 03 '15 at 13:35
  • So thanks I guess for the link to the other post, I can edit my original post with the following if that will help? Perhaps I should have specified, I'm not looking to write cross-platform code I'm coding for Linux only (Debian/Ubuntu), if possible I'd rather not include an extra library either. I was looking for a way to achieve 9 points of precision exactly using doubles. As it goes I only need a total of 18 points of "significance", 9 digitals before the decimal place and 9 digitis after. This is something that on any 64 byte system I would assume (as a C novice) would be fairly trivial. – jwbensley Sep 03 '15 at 15:46
  • 1
    You have your answer. Do all your math with `int64_t` (or `long long`) except for I/O. Read "123456789.123456789" into `long double ld`, and covert to `int64_t y = roundl(ld*1000000000.0)`. To print, `printf("%.9Lf", y/1000000000.0L)`. Typical `double` cannot maintain 18 decimal digits on linear precision. Typical `long double` can. – chux - Reinstate Monica Sep 03 '15 at 16:00
  • @chux I see, so for my small-ish precision requirements a `long long` and `long double` will suffice. Thank you very much – jwbensley Sep 03 '15 at 18:51
  • 1
    `long long`, by spec., handles at least +/-9e18 (your 18 digit requirement). `long double` _very likely_ handles a similar range and more - it certainly handles at least 10 digits. – chux - Reinstate Monica Sep 03 '15 at 19:30

0 Answers0