0

When representing double number its precision corrupts in some degree. For example number 37.3 can be represented as 37.29999999999991.

I need reestablishing of corrupted double number (My project requires that). One approach is converting double into CString.

double d = 37.3;
CString str;
str.Format("%.10f", d);

Output: str = 37.3;

By this way I could reestablish corrupted d. However, I found a counterexample. If I set

d = 37.3500;

then its double representation sometimes be equal to 37.349998474121094. When converting d to CString output is still 37.3499984741, which is not equal to 37.3500 actually.

Why converting 37.3500 didn't give desired answer, while 37.3 gave? Is there any ways to reestablish double?

Thanks.

Nurlan
  • 2,860
  • 19
  • 47
  • 64
  • 1
    You could try `snprintf` with `%g`. – chris Jan 13 '14 at 12:31
  • 3
    it is not "corrupted", it is the floating point representation. You can't un-corrupt floating point precision. If you need decimal accuracy, then you need a dedicated decimal type. – Stephane Rolland Jan 13 '14 at 12:38
  • no no, @ chris, snprintf with %g rounds up to 4 decimal places. I need 10 decimal places at least.. – Nurlan Jan 13 '14 at 12:54
  • 2
    So what would you do about *exactly* 37.29999999999991? If you round it to 37.3 (using `sprintf` or whatever method) it will also get "corrupted"... – molbdnilo Jan 13 '14 at 12:54

2 Answers2

4

Why converting 37.3500 didn't give desired answer, while 37.3 gave?

By accident. The representation of 37.3 happened to be close enough that rounding to 10 decimal places gave the expected result, while 37.3499984741 didn't.

Is there any ways to reestablish double?

No, once information has been lost, you can't recover it. If you need an exact representation of decimal numbers, then you'll need a different format than binary floating point. There's no suitable decimal type in the C++ language or standard library; depending on your needs, you might consider libraries such as Boost.Multiprecision or GMP. Alternatively, if you can limit the number of decimal places you need, you might be able to multiply all your numbers by that scale and work with exact integers.

Mike Seymour
  • 249,747
  • 28
  • 448
  • 644
0

It can be done to some extend, but not easily. Since the string representation is base 10, but the internal representation in base 2, there is rounding involved when converting one into the other. So when you convert the decimal "37.35" to double, the result is not identical to the original number. When converting that number back to a string, the computer cannot know for sure what number was there in the first place, because there are several decimal numbers that result in the same double. However, you can add the constraint that you want the shortest possible decimal string that results in the given double, then there is a very good chance that it recovers your original string precisely. An algorithm using that constraint has been developed by David Gay. Here's the source code, you need both g_fmt.c and dtoa.c, and here is a paper about it. This is the default algorithm used in Python since Version 3.1.

pentadecagon
  • 4,717
  • 2
  • 18
  • 26