【问题标题】:Incorrect rounding of float when using ToString("F1")使用 ToString("F1") 时浮点数舍入不正确
【发布时间】:2012-12-28 19:29:59
【问题描述】:

我有一个浮点值:12345.6489

当我使用以下格式对其进行格式化时:

(12345.6489f).ToString("F1")

然后我得到一个结果

12345.7

但这是不正确的,因为它应该是 12345.6。

有人明白为什么会发生这种情况吗?另一个提示是,在我格式化之前强制转换为双精度会返回正确的结果,如果我的浮点值小一点,例如 1234.6489,那么我也会得到正确的结果。

【问题讨论】:

  • @DavidStratton:Double 也不准确,并且会给出类似的奇怪现象。它们只是具有不同的精度和不同的范围。
  • @JonSkeet - 感谢您的澄清!我删除了评论。
  • Single.ToString 正在做一些非常奇怪的事情。我认为您需要查看IL。文档 (msdn.microsoft.com/en-us/library/f71z6k0c.aspx) 说“默认情况下,返回值仅包含 7 位精度,尽管内部维护最多 9 位”但我确定我不知道这意味着什么。
  • 嗯,[MethodImpl(MethodImplOptions.InternalCall)],所以没有 IL。
  • @DavidHeffernan 值得注意的是,虽然在大多数区域中,float 比具有 7 个有效数字的十进制数更精确,但也有一些地方这不是真的。在这些地区,你会得到有趣的结果,因为ToString() 给出了 7 个十进制数字。示例:在9E+09f(90 亿)附近,7 位小数的精度为1000,而float 的精度仅为1024。因此,例如float x = 9E+09f; Console.WrireLine(x); 给出了一个惊喜(9,000,000,000 是 512 模 1024)。

标签: c# string floating-point format


【解决方案1】:

这好像和我前段时间问的一个问题有关: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");

【讨论】:

    【解决方案2】:

    感谢您提出这个问题!从事调查是非常有趣的课题。但我想说的是另一方的奖牌。你问了以下问题:

    (12345.6489f).ToString("F1")

    然后我得到一个结果

    12345.7

    但这是不正确的,因为它应该是 12345.6。

    好吧,我想知道您是如何知道什么是正确以及什么是不正确输出这个字符串格式化程序?这些格式化字符串不应该用于舍入目的。并且文档清楚地says 关于它:


    老实说,当我第一次从您的问题中查看数字时 - 第一个想法是 Hans Passant 在他的回答中提到的舍入算法。所以,我什至不会对选择这样的算法感到惊讶,它实际上非常直观:) 我什至不会惊讶他们会考虑将普通截断作为浮点数格式化的算法。它仍然非常准确和有效。

    所以,尽管事实上所有 这很有趣,看起来像一个错误/悖论/奇迹,这实际上只是我们对这个功能的错误期望,它旨在做(实际上做得很好)另一件事。

    【讨论】:

    • 啊,我以为我在某处读到字符串格式应该为您取整数字,这就是为什么我认为 12345.6 是正确答案的原因。是的,Math.Round 肯定会更可靠!
    • Math.Round 根本没有帮助。这将返回一个浮点值。您仍然需要获取一个带您返回 ToString 的字符串。您需要四舍五入作为转换为字符串的一部分。这很关键,因为浮点使用二进制表示,但字符串表示是十进制。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-16
    • 2010-12-11
    • 1970-01-01
    • 2018-04-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多