ZetCode

C# Decimal

最后修改于 2023 年 7 月 5 日

C# Decimal 教程展示了如何在 C# 中使用 Decimal 进行高精度计算。

Decimal

decimal 是一种浮点十进制类型。 由于 decimal 类型比 float 和 double 具有更高的精度和更小的范围,因此它适用于财务和货币计算。 Decimal 的默认值为 0。Decimal 字面量使用 mM 后缀。 人们习惯于用十进制形式表示非整数,并期望在十进制表示中获得精确的结果。

有些值不能用 double/float 数据类型精确表示。 例如,将 0.1 值存储在 double/float(它们是二进制浮点值)变量中,我们只能获得该值的近似值。 同样,1/3 的值不能用十进制浮点类型精确表示。

Decimal 比 double/float 慢得多。 Decimal 还允许编码或尾随零。

这两种类型都不是完美的;一般来说,decimal 类型更适合财务和货币计算,而 double/float 类型更适合科学计算。

C# 浮点数

浮点数表示计算机中的实数。实数测量连续的量,如重量、高度或速度。在 C# 中,我们有三种浮点类型:floatdoubledecimal

C# 别名 .NET 类型 大小 精度 范围
float System.Single 4 字节 7 位数字 +-1.5 x 10-45 到 +-3.4 x 1038
double System.Double 8 字节 15-16 位数字 +-5.0 x 10-324 到 +-1.7 x 10308
decimal System.Decimal 16 字节 28-29 位小数 +-1.0 x 10-28 到 +-7.9 x 1028

上表给出了浮点类型的特征。

注意: 根据经验,decimal 用于计数的值,而 float/double 用于测量的值。

C# decimal 精度

decimal 类型是一个 128 位浮点数据类型;它最多可以有 28-29 位有效数字。

以下示例比较了 floatdoubledecimal 类型的精度。

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

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

值 1/3 是一个非终止数字;它只能表示为近似值。

$ dotnet run
0.33333334
0.3333333333333333
0.3333333333333333333333333333

从示例中我们可以看到,decimal 在小数点后有更多的小数位。

C# decimal 字面量

D/d 后缀用于 double 值,F/f 用于 float 值,M/m 用于 decimal 值。 没有后缀的浮点值是 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());

在本例中,我们对浮点数使用了三种不同的字面量表示法。

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

C# decimal 用于精确的财务或货币计算

财务和货币计算必须是精确的。

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);

此示例显示值 0.1 可以用 decimal 类型精确表示。

$ dotnet run
0.30000000000000004
0.3
False
0.3
0.3
True

double 值有一些小错误。在许多计算中可以忽略它。 例如,如果我们测量人的体重或身高,这种错误是无关紧要的。 但是,在财务计算中,它会导致问题。

C# decimal System.OverflowException

与 double/float 类型不同,尝试将 decimal 值增加到超出其限制会导致 System.OverflowException

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

Console.WriteLine(maxValue.ToString("f"));
Console.WriteLine(nextValue.ToString("f"));

decimal maxValue2 = decimal.MaxValue;
decimal nextValue2 = maxValue2 + 1m;

Console.WriteLine(maxValue.ToString("m"));
Console.WriteLine(nextValue.ToString("m"));

在示例中,我们将 floatdecimal 的最大值都加 1。

$ dotnet run 
340282346638528859811704183484516925440.000
340282346638528859811704183484516925440.000 
Unhandled exception. System.OverflowException: Value was either too large or too 
small for a Decimal.
...

该示例抛出 System.OverflowException

C# decimal Parse

Parse 方法将数字的字符串表示形式转换为其 decimal 等效项。

numbers.txt
123.23
213.44
713.54
319.11
199.09

我们有这个 numbers.txt 文件。

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

decimal sum = 0m;

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

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

在此示例中,我们从 numbers.txt 文件中读取所有值。

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

ReadAllLines 返回一个字符串数组。 我们需要将字符串转换为 decimal 值。

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

我们遍历数组并使用 Parse 将字符串解析为 decimals。

$ dotnet run
The sum is: 1568.41

C# decimal 内置方法

decimal 类型有一些内置方法,例如 AddSubtract

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));

该示例演示了 RemainderAddSubtractRound 方法。

$ dotnet run
2
17
7
12.9

来源

Decimal 结构体

在本文中,我们使用了 C# 中的 Decimal 数据类型。

作者

我叫 Jan Bodnar,是一位热情的程序员,拥有丰富的编程经验。 我从 2007 年开始撰写编程文章。 至今,我已撰写超过 1,400 篇文章和 8 本电子书。 我拥有超过十年的编程教学经验。

列出所有 C# 教程