Home > Blockchain >  How to accurately multiply a COleCurrency by a double?
How to accurately multiply a COleCurrency by a double?

Time:02-16

I have a COleCurrency object that represents a unit price. And I have a double value that represents a quantity. And I need to calculate the total dollar amount to the nearest penny.

Looks like COleCurrency has built in multiplication operators, but only for multiplication with a long value.

I can multiply COleCurrency.m_cur.int64 by the double, but that converts the double to __int64 so it wouldn't be accurate.

What is the best way to accurately multiply a COleCurrency by a double?

CodePudding user response:

Finite binary floating point values form a proper subset of finite decimal values. While any given floating point value has an exact, finite representation in decimal, the opposite isn't true. In other words, not every decimal can be represented using a finite binary floating point value. A simple example is 0.1 that produces an infinite sequence of binary digits when converted to a binary floating point value.

The important point here is that if you are dealing with fractional values, using binary floating point values to represent them will in general introduce inaccuracies (with very few exceptions, such as 0.5). The only way to perform accurate multiplications with an integer value is to use an integer as the multiplicand.

Since you have opted to use a floating point value the only thing you can do is limit the inaccuracies. The proposed solution:

__int64 x = currency.m_cur.int64 * (__int64)dbl;

suffers from the same "possible loss of data" issue the compiler warned about. Since you're now using an explicit cast, this silences the compiler. The effect is still the same: The floating point value gets truncated.

A better approach would be to convert the 64-bit integer value to a double first. This produces an exact floating point representation of the integer value, provided that it is within range (roughly /- 1e15). You can then multiply with another floating point value (which is subject to rounding errors), and finally round the result using, e.g., std::llround:

__int64 x = std::llround(static_cast<double>(currency.m_cur.int64) * dbl);
  • Related