我有一个浮点值:12345.6489
当我使用以下方法格式化它时:
(12345.6489f).ToString("F1")
然后我得到结果
12345.7
但是这是不正确的,因为它应该是 12345.6。
有谁明白为什么会发生这种情况?另一个提示是,在格式化之前转换为 double 会返回正确的结果,如果我的浮点值稍小一些,例如 1234.6489,那么我也会得到正确的结果。
这似乎与我前段时间问过的一个问题有关:Round-twice error in .NET's Double.ToString method
请注意,如果您拨打号码上的
.ToString("G")
,则该号码会正确舍入为 12345.65
。如果将四舍五入后的数字四舍五入到小数点后一位,就会出现问题。
当我之前调查自己的问题时,我还发现了一些无法解释为两次循环错误的示例,因此也请检查该线程。
加法: 请注意,任何可以由
float
(精确地)表示的数字也可以由 double
表示(带有大量零位)。人们可以使用以下技巧(问题也提到了):
float x = 12345.6489f;
string trick = ((double)x).ToString("F1");
谢谢你的提问!从事调查是非常有趣的课题。但我想提一下奖牌的另一方。您问了以下问题:
(12345.6489f).ToString("F1")
然后我得到结果
12345.7
但是这是不正确的,因为它应该是 12345.6。
好吧,我想知道你是如何弄清楚这个字符串格式化例程的输出是什么正确以及什么是不正确?这些格式化字符串不应该用于舍入目的。文档清楚地说:
老实说,当我第一次查看你问题中的数字时 - 第一个想法是汉斯·帕桑特在他的回答中提到的舍入算法。因此,我什至对选择这样的算法并不感到惊讶,它实际上非常直观:)我什至不会感到惊讶他们会考虑将普通截断作为浮点数格式化的算法。它仍然相当准确和有效。
所以,尽管事实上所有 这非常有趣,看起来像一个错误/悖论/奇迹,这实际上只是我们对这个函数的错误期望,该函数旨在做(并且实际上做得很好)另一件事。
我相信解释是
float.ToString()
按解释的方式进行了两次这里
以下 C# 代码:
float f = #NUMBER BETWEEN 10000 AND 100000#;
Console.WriteLine(f.ToString("f1"));
以及以下 C 语言代码:
float f = #NUMBER BETWEEN 10000 AND 100000#;
printf("%.1f", f + 5e-3);
应该产生相同的输出。特别是 C# 代码:
float f = 12345.6489f;
Console.WriteLine(f.ToString("f1"));
产生
12345.7
和 C 代码:
float f = 12345.6489f;
printf("%.1f", f + 5e-3);
还产生
12345.7