ZetCode

C# Decimal

last modified October 15, 2026

In this article we show how to perform high-precision calculations in C# with the decimal type.

Decimal

The decimal is a floating decimal point type; it is an alias for the System.Decimal structure. Because the decimal type has more precision and a smaller range than both float and double, it is appropriate for financial and monetary calculations. The default value of a decimal is 0. A decimal literal uses the m or M suffix. Humans are used to representing non-integers in a decimal form, and expect exact results in decimal representations.

Some values cannot be exactly represented in the double and float data types. For instance, when we store the 0.1 value in a double or float variable (which are binary floating point types), we get only an approximation of the value. Similarly, the 1/3 value cannot be represented exactly in the decimal floating point type.

Decimal calculations are much slower than double or float calculations. Decimals also preserve trailing zeros.

Neither of the types is perfect; generally, decimal types are better suited for financial and monetary calculations, while the double/float types for scientific calculations.

C# floating point numbers

Floating point numbers represent real numbers in computing. Real numbers measure continuous quantities, like weight, height, or speed. In C# we have three floating point types: float, double, and decimal.

C# Alias .NET Type Size Precision Range
float System.Single 4 bytes ~6-9 digits ±1.5 x 10-45 to ±3.4 x 1038
double System.Double 8 bytes ~15-17 digits ±5.0 x 10-324 to ±1.7 x 10308
decimal System.Decimal 16 bytes 28-29 digits ±1.0 x 10-28 to ±7.9228 x 1028

The above table gives the characteristics of the floating point types.

Note: As a rule of thumb, decimal is used for counted values while float and double are used for measured values.

C# decimal precision

The decimal type is a 128-bit floating point data type; it can have 28-29 significant digits.

The following example compares the precision of the float, double, and the decimal types.

Program.cs
float x = 1f / 3f;
double y = 1d / 3d;
decimal z = 1m / 3m;

Console.WriteLine(x);
Console.WriteLine(y);
Console.WriteLine(z);

The value 1/3 is a non-terminating number; it can be represented only as an approximation.

$ dotnet run
0.33333334
0.3333333333333333
0.3333333333333333333333333333

From the example we can see that decimal has the most digits after the decimal point.

C# decimal literal

The D/d suffix is used for double values, the F/f for float values and the M/m for decimal values. Floating point values without a suffix are double.

Program.cs
float n1 = 1.234f;
double n2 = 1.234;
decimal n3 = 1.234m;

Console.WriteLine(n1);
Console.WriteLine(n2);
Console.WriteLine(n3);

Console.WriteLine(n1.GetType());
Console.WriteLine(n2.GetType());
Console.WriteLine(n3.GetType());

In the example, we use three different literal notations for floating point numbers.

$ dotnet run
1.234
1.234
1.234
System.Single
System.Double
System.Decimal

C# decimal for exact financial or monetary calculations

Financial and monetary calculations must be exact.

Program.cs
double x = 0.1 + 0.1 + 0.1;
double y = 0.3;

Console.WriteLine(x);
Console.WriteLine(y);
Console.WriteLine(x == y);

decimal u = 0.1m + 0.1m + 0.1m;
decimal v = 0.3m;

Console.WriteLine(u);
Console.WriteLine(v);
Console.WriteLine(u == v);

The example shows that the value 0.1 can be represented exactly in the decimal type, but not in the double type.

$ dotnet run
0.30000000000000004
0.3
False
0.3
0.3
True

The double value has some small error. It can be ignored in many calculations. For instance, if we are measuring the weight or height of people, this kind of error is irrelevant. However, in financial calculations it causes problems.

C# decimal trailing zeros

Unlike double, a decimal value stores its scale, that is, the number of digits after the decimal point. Therefore, trailing zeros are preserved.

Program.cs
decimal a = 1.5m;
decimal b = 1.50m;
decimal c = 1.500m;

Console.WriteLine(a);
Console.WriteLine(b);
Console.WriteLine(c);
Console.WriteLine(a == b && b == c);

Console.WriteLine(c.Scale);
Console.WriteLine(1.10m * 2.0m);

The three values are equal, but they are printed with a different number of digits.

Console.WriteLine(c.Scale);

The Scale property returns the scaling factor of the value; that is, the number of digits after the decimal point.

Console.WriteLine(1.10m * 2.0m);

In multiplication, the scale of the result is the sum of the scales of the operands.

$ dotnet run
1.5
1.50
1.500
True
3
2.200

C# decimal System.OverflowException

Unlike in double/float types, trying to increase a decimal value beyond its limit causes System.OverflowException.

Program.cs
float maxValue = float.MaxValue;
float nextValue = maxValue + 1f;

Console.WriteLine(maxValue);
Console.WriteLine(nextValue);
Console.WriteLine(maxValue == nextValue);

decimal maxValue2 = decimal.MaxValue;
Console.WriteLine(maxValue2);

decimal nextValue2 = maxValue2 + 1m;
Console.WriteLine(nextValue2);

In the example, we add one to the maximal value of a float and a decimal.

float nextValue = maxValue + 1f;

Adding one to the maximal float value silently produces the same value, because the result is rounded to the nearest representable number.

decimal nextValue2 = maxValue2 + 1m;

The same operation with decimal throws an exception.

$ dotnet run
3.4028235E+38
3.4028235E+38
True
79228162514264337593543950335
Unhandled exception. System.OverflowException: Value was either too large or too small for a Decimal.
...

The example throws the System.OverflowException.

C# decimal Parse

The Parse method converts the string representation of a number to its decimal equivalent.

numbers.txt
123.23
213.44
713.54
319.11
199.09

We have this numbers.txt file.

Program.cs
using System.Globalization;

var values = File.ReadAllLines("numbers.txt");

decimal sum = 0m;

foreach (var value in values)
{
    sum += decimal.Parse(value, CultureInfo.InvariantCulture);
}

Console.WriteLine($"The sum is: {sum}");

In the example, we read all values from the numbers.txt file.

var values = File.ReadAllLines("numbers.txt");

The ReadAllLines returns a string array. We need to transform the strings into decimal values.

foreach (var value in values)
{
    sum += decimal.Parse(value, CultureInfo.InvariantCulture);
}

We go through the array and parse the strings into decimals with Parse. We pass the invariant culture, which uses the dot as the decimal separator. Without it, the parsing would depend on the current culture of the system; in many cultures the decimal separator is a comma.

$ dotnet run
The sum is: 1568.41

C# decimal built-in methods

The decimal type has some built-in methods such as Add or Subtract.

Program.cs
decimal x = 12m;
decimal y = 5m;
decimal z = 12.89m;

Console.WriteLine(decimal.Remainder(x, y));
Console.WriteLine(decimal.Add(x, y));
Console.WriteLine(decimal.Subtract(x, y));
Console.WriteLine(decimal.Round(z, 1));

The example demonstrates the Remainder, Add, Subtract, and Round methods.

$ dotnet run
2
17
7
12.9

C# decimal rounding

By default, decimal.Round uses the banker's rounding (MidpointRounding.ToEven); a midpoint value is rounded to the nearest even number. The rounding strategy can be changed with the MidpointRounding parameter.

Program.cs
decimal[] vals = [2.345m, 2.355m, -2.345m];

foreach (var val in vals)
{
    var r1 = decimal.Round(val, 2);
    var r2 = decimal.Round(val, 2, MidpointRounding.AwayFromZero);
    var r3 = decimal.Round(val, 2, MidpointRounding.ToZero);

    Console.WriteLine($"{val}: {r1} {r2} {r3}");
}

We round three values to two decimal places using three different strategies.

$ dotnet run
2.345: 2.34 2.35 2.34
2.355: 2.36 2.36 2.35
-2.345: -2.34 -2.35 -2.34

Since decimal represents these values exactly, the midpoint rules are applied as expected. With double, a value such as 2.345 might be stored as slightly less or more than the midpoint.

Source

Decimal struct

In this article we have worked with the decimal data type in C#.

Author

My name is Jan Bodnar, and I am a passionate programmer with extensive programming experience. I have been writing programming articles since 2007. To date, I have authored over 1,400 articles and 8 e-books. I possess more than ten years of experience in teaching programming.

List all C# tutorials.