提问人:Tom Charles Zhang 提问时间:10/17/2023 最后编辑:Tom Charles Zhang 更新时间:10/29/2023 访问量:153
C# 格式浮点舍入/准确性问题:N2 与 0.00
C# Formatting Floating Point Rounding/Accuracy Issue: N2 vs 0.00
问:
在 C# (.Net 7) 中:
float a = 13082987520.00f;
Console.WriteLine(a);
Console.WriteLine($"{a:N2}");
Console.WriteLine($"{a:0.00}");
我得到:
1.3082988E+10
13,082,987,520.00
13082990000.00
特别要注意最后两行之间的数字差异:
13082987520
vs
13082990000
当我尝试将此类数字编写为 CSV 文件时,这引起了很多混乱。 在这种预期行为中? 我们该如何解释呢?
请注意,这个问题与 ToString(“N2”) 和 ToString(“0.00”) 之间的区别非常不同。我知道在格式方面的差异,但在这里我指出浮点数打印的一个潜在的意想不到的实现细节(以及潜在的错误?如上例所示,显然“N2”不仅仅是添加千个分隔符,而“0.00”则不会。
double 不存在同样的问题:
double b = 13082987520.00;
Console.WriteLine(b);
Console.WriteLine($"{b:N2}");
Console.WriteLine($"{b:0.00}");
13082987520
13,082,987,520.00
13082987520.00
这里的问题是:
- 哪个是(单个)浮点的“正确”浮点?(实际上就是印有“N2”的那个)
- 如何在不做的情况下打印正确的(即使用“N2”显示的那个)?
a.ToString("N2").Replace(",", string.Empty)
答:
摘自 ECMA-334:2022 C# 语言标准,第 8.3.7 章:
浮点类型
...
该类型可以表示值...精度为 7 位。
float
(在这个问题中,有关浮点近似的更多信息,简单的 32 位 IEEE 浮点数不能提供超过 7 位的精度)
因此,这两个值都是正确的近似值,四舍五入到 7 位的两个值都提供相等的四舍五入值:
13082987520
13082990000
^
|
1234567
浮点数适用于近似值。对于精确值(因此,例如用于货币计算),您应该改用。来自同一标准第 8.3.8 章:decimal
该类型是 128 位数据类型,适用于财务和货币计算。
decimal
评论
比较在 .NET Framework 4.8.1 和 .NET 7 下运行的代码的行为很有启发性:
// .NET FX 4.8.1 | .NET 7
Console.WriteLine(a); // 1.308299E+10 | 1.3082988E+10
Console.WriteLine(a.ToString("N2")); // 13,082,990,000.00 | 13,082,987,520.00
Console.WriteLine(a.ToString("0.00")); // 13082990000.00 | 13082990000.00
这些格式化的值中哪一个是正确的?
可以说,所有这些都是“正确的”。它们同意精度的七位十进制数字的值,这是数据类型承诺支持的全部内容。a
float
为什么 .NET Framework 和 .NET 7 之间的格式化值不同?
.NET Core 3.0 改进了浮点格式代码,使其符合 IEEE 754-2008 标准。 现在返回最短的往返字符串,而返回精确浮点值中可用的所有数字。ToString()
ToString("N2")
在 .NET 7 中,为什么自定义格式字符串(如“0.00”)在七位数字后舍入值?float
显然,此行为是为了向后兼容:
// SinglePrecisionCustomFormat and DoublePrecisionCustomFormat are used to ensure that
// custom format strings return the same string as in previous releases when the format
// would return x digits or less (where x is the value of the corresponding constant).
private const int SinglePrecisionCustomFormat = 7;
如何获得与“N2”相同但不带逗号的值?
请尝试改用“F2”定点格式:
Console.WriteLine($"{a:F2}"); // 13082987520.00
评论
F2
下一个:浮点数学坏了吗?
评论