Where is the floating point problem in this C# fin

2019-08-27 04:38发布

问题:

I receive a FIX message for a trade Allocation, where Price is given in cents (ZAR / 100), but commission is given in Rands. These values are represented by the constants. When I run this calculation, commPerc1 shows a value of 0.099999999999999978, and commPerc2 shows 0.1. These values look to differ by x10, yet with the check of calculating back to Rands, both commRands1 and commRands2 show very similar values of 336.4831554 and 336.48315540000004 respectively.

private const double Price = 5708.91;
private const double Qty = 5894;
private const double AbsComm = 336.4831554;

static void Main()
{

    double commCents = AbsComm * 100;
    double commPerc1 = commCents / (Qty * Price) * 100;
    double commRands1 = (Qty * Price) * (commPerc1 / 100) / 100;

    double commPerc2 = (AbsComm / (Qty * (Price / 100))) * 100;
    double commRands2 = (Qty * Price) * (commPerc2 / 100) / 100;
}

PLEASE NOTE: I am dealing with legacy code here where a conversion to decimal would involve several changes and QA, so right now I have to accept double.

回答1:

Don't use double for financial calculations, use decimal instead. Floating point numbers are OK for physical, measured values, where the value is never exact anyway. But for financial calculations you're working with exact values, you can't afford errors due to floating point representations. That's what decimal is made for:

The Decimal value type is appropriate for financial calculations requiring large numbers of significant integral and fractional digits and no round-off errors.

(from MSDN)



回答2:

The floating point problem is everywhere, because all of your values are of type double, which is a double-precision floating-point type, not a base-10 numeric type. (Hence, all calculations being performed are floating-point calculations.)

You should declare your variables decimal instead. That type is purposed precisely for financial calculations.



回答3:

When I run this calculation, commPerc1 shows a value of 0.099999999999999978, and commPerc2 shows 0.1. These values look to differ by x10

No they don't. There is only an infinitely small (but existing) rounding difference between. As others have already noted, you should never use floating point with calculations that demand absolute precision. With floating point you always have rounding errors like this, and e.g. financial clients don't like missing or extra pennies/cents in their books.



回答4:

That's due to the way floating numbers are stored in memory. You could use decimal instead of double or float when dealing with financial calculations.



回答5:

Financial calculations should be carried out using the Decimal datatype. Doubles store 'approximations' of the specified number since the specified number can't be stored perfectly within the specified bit-allocation.



回答6:

0.099999999999999978 and 0.1 don't differ by a factor of 10, they are almost the same. Just like 0.999 is almost 1.

But you really should use Decimal instead of Double for financial calculations. Double can't exactly represent numbers like 0.1 whereas Decimal can. (On the other hand neither can represent 1/3 exactly).

Additionally Decimal has a larger mantissa and throws exceptions when overflows occur.



回答7:

Please use decimal for monetary calculations.

Have a look Here