3

The code below would result in moneyDouble = 365.24567874299998 and I need it to be exactly 365.245678743
I wouldn't mind having to set a precision and getting some extra zeros to the right.

This number is used to calculate money transaction so it needs to be exact.

std::string money ("365.245678743");
std::string::size_type sz;     // alias of size_t

double moneyDouble = std::stod (money,&sz);
frogatto
  • 28,539
  • 11
  • 83
  • 129
Tom
  • 93
  • 2
  • 7
  • That's not really possible because of how floating point numbers work on binary computers, where not all numbers can be exactly represented. – Some programmer dude May 19 '18 at 17:28
  • Any answer is platform specific and fragile. However in practice (i.e. my machine) if you print a double with about 16 digit (use `std::precision`) you can reconstruct the number exactly in all cases I tried. To control the precision you can use `std::stringstream` or some formatting library. See for example https://stackoverflow.com/q/44739874/225186 and similar questions. `std::numeric_limits` will make it a little bit more portable in some sense. – alfC May 19 '18 at 18:40
  • @alfC Actually, for IEEE-754 numbers, it's 9 decimal digits for single-precision, and 17 decimal digits for double-precision. That guarantees you perfect round-trips in both directions. – Angew is no longer proud of SO May 20 '18 at 13:15

2 Answers2

2

Floating-point numbers and exact precision don't mix, period [link]. For this reason, monetary calculations should never be done in floating-point [link]. Use a fixed-point arithmetic library, or just use integer arithmetic and interpret it as whatever fractional part you need. Since your precision requirements seem to be very high (lots of decimals), a big number library might be necessary.

While library recommendations are off-topic on Stack Overflow, this old question seems to offer a good set of links to libraries you might find useful.

Angew is no longer proud of SO
  • 167,307
  • 17
  • 350
  • 455
1

The result of your erroneous output of moneyDouble is because moneyDouble is a floating point number. They cannot express tenths, hundredths, thousandths, etc exactly.

Furthermore, floating-point numbers are really expressed in binary form, meaning that only (some) binary numbers can be expressed exactly in floating point. Not to mention that they have finite accuracy, so they can only store only a limited number of digits (including those after the decimal point).

Your best bet is to use fixed-point arithmetic, integer arithmetic, or implement a rational-number class, and you might need number libraries since you may have to deal with very big numbers in very high precision.

See Is floating point math broken? for more information about the unexpected results of floating-point accuracy.