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.
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.
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.
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.
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.
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.
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.
123.23 213.44 713.54 319.11 199.09
We have this numbers.txt file.
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.
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.
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
In this article we have worked with the decimal data type in C#.
Author
List all C# tutorials.