Jul 23

Pro Tip: Never use type double for money / financial applications

Pro Tip: Never use type double for money / financial applications

When you are new into coding financial applications one of the mistakes people tend to do is using a data type that it’s precision / significant digits are not enough to properly represent numers. If you’ve taken some CS classes you know how decimals are represented in a computer system; They are fractions.

To avoid this common pitfall, there are a variety of techniques. One for example, is that if you need only 4 positions after the decimal place you simply store them as integers on the backend and dividing them by a power of 10 when presenting them. Some languages offer support of this behind scenes. Take for example System.Decimal in .Net; It is still a floating point but instead of being a floating binary point it is a floating decimal point, and that makes all the difference.

If you don’t believe me, try this code to see how a double won’t work for a financial/money application:

using System;

class Test
{
    static void Main()
    {
        double x = 0.1;
        double y = x + x + x;
        Console.WriteLine(y == 0.3); // Prints False
    }
}

So if you are using .Net, you should consider using System.Decimal since decimal uses a scaling factor of multiples of 10, numbers like 0.1 can be represented exactly. In essence, the decimal type represents this as 1 / 10 ^ 1, whereas a double would represent this kind of like 104857 / 2 ^ 20.

A decimal can exactly represent any base 10 value with up to 28/29 significant digits (like 0.1).

References:

decimal (C# Reference) https://msdn.microsoft.com/en-us/library/364x0z75.aspx

decimal (C# Reference)

Visual Studio 2015
  The decimal keyword indicates a 128-bit data type. Compared to floating-point types, the decimal type has more precision and a smaller range, which makes it appropriate for financial and monetary calculations. The approximate range and precision for the decimal type are shown in the following table.
Type Approximate Range Precision .NET Framework type
decimal (-7.9 x 1028 to 7.9 x 1028) / (100 to 28) 28-29 significant digits System.Decimal

If you want a numeric real literal to be treated as decimal, use the suffix m or M, for example:

decimal myMoney = 300.5m;

Without the suffix m, the number is treated as a double and generates a compiler error.

The integral types are implicitly converted to decimal and the result evaluates to decimal. Therefore you can initialize a decimal variable using an integer literal, without the suffix, as follows:

 decimal myMoney = 300;

There is no implicit conversion between floating-point types and the decimal type; therefore, a cast must be used to convert between these two types. For example:

decimal myMoney = 99.9m;
double x = (double)myMoney;
myMoney = (decimal)x;

You can also mix decimal and numeric integral types in the same expression. However, mixing decimal and floating-point types without a cast causes a compilation error.

For more information about implicit numeric conversions, see Implicit Numeric Conversions Table (C# Reference).

For more information about explicit numeric conversions, see Explicit Numeric Conversions Table (C# Reference).

Formatting Decimal Output

You can format the results by using the String.Format method, or through the Console.Write method, which calls String.Format(). The currency format is specified by using the standard currency format string “C” or “c,” as shown in the second example later in this article. For more information about the String.Format method, see String.Format.

Leave a Reply

%d bloggers like this: