【问题标题】:c# floating point for loop, unexpected resultsc#浮点for循环,意外结果
【发布时间】:2012-07-06 15:16:02
【问题描述】:

谁能向我解释为什么这个程序:

for(float i = -1; i < 1; i += .1F)
    Console.WriteLine(i);

输出这个:

-1

-0.9

-0.8

-0.6999999

-0.5999999

-0.4999999

-0.3999999

-0.2999999

-0.1999999

-0.99999993

7.450581E-08

0.1000001

0.2000001

0.3000001

0.4000001

0.5000001

0.6000001

0.7000001

0.8000001

0.9000002

舍入误差从何而来??

【问题讨论】:

标签: c# for-loop floating-point


【解决方案1】:

我确信这个问题之前一定有人以某种形式提出过,但我无法在任何地方快速找到它。 :)

答案归结为浮点数的表示方式。您可以进入technical detail via wikipedia,但简单地说,十进制数不一定具有精确的浮点表示...

浮点数(无论如何都像双精度和浮点数一样以 2 为底的浮点数)的工作方式 [0] 是通过将 1/2 的幂相加得到你想要的。所以 0.5 只是 1/2。 0.75 是 1/2+1/4 等等。

问题来了,如果没有 2 的越来越小的幂的无穷无尽的流,你永远无法在这个二进制系统中表示 0.1,因此计算机能做的最好的事情就是存储一个非常接近但不完全是 0.1 的数字。

通常您不会注意到这些差异,但它们确实存在,有时您可以让它们表现出来。有很多方法可以处理这些问题,而您使用哪一种在很大程度上取决于您实际处理它的方式。

[0] 以稍微接近的方式

【讨论】:

    【解决方案2】:

    浮点数不正确,它们总是近似的,因为它们必须四舍五入!!
    它们在二进制表示中是精确的。
    每个 CPU 或 pc 都可能导致不同的结果。
    看看Wikipedia page

    【讨论】:

    • 这不是真的。正如我已经得到纠正的那样,FP 是精确的,但它们在二进制中是精确的。这是近似的转换为十进制,因为它必须经常四舍五入。
    • 有限二进制分数始终可以表示为有限十进制数。原因是 (1/2)^n 永远不是重复数字,因此它们的总和不会重复出现。所以你可以得到一个精确的十进制表示,它只取决于你的数字有多宽。它只是从十进制到二进制的转换,不能总是以精确的方式完成(尽管值得注意的是,并非所有小数在成为二进制浮点数时都会失去精度)。
    【解决方案3】:

    最大的问题是0.1 不能用二进制表示,就像1 / 31 / 7 不能用十进制表示一样。所以由于计算机在某些时候必须中断,它会累积一个舍入误差。

    尝试在几乎任何编程语言中使用0.1 + 0.7 == 0.8,结果会是错误的。

    在 C# 中要解决此问题,请使用 decimal 类型以获得更好的精度。

    【讨论】:

      【解决方案4】:

      【讨论】:

        【解决方案5】:

        舍入误差来自浮点不是精确数据类型(转换为十进制时),它是一个近似值,注意C# Reference 浮点被指定为具有 7 位小数精度。

        【讨论】:

        • 这不是真的,它没有回答问题。
        • 这个问题得到了很好的回答——答案是,舍入误差来自浮点数中缺少小数精度。 Microsoft C# Reference 很清楚,精度只有 7 位——OP 列表的值是 7 位长...
        • 将浮点数转换为小数不是问题。将小数转换为浮点数就是问题所在。浮点数的大小(和精度)意味着它始终可以准确地表示为小数。
        【解决方案6】:

        它是任何浮点变量的基础。原因很复杂,但如果你用谷歌搜索的话,会有很多信息。

        尝试使用 Decimal。

        【讨论】:

          【解决方案7】:

          正如其他海报所暗示的那样,问题源于浮点数是精确十进制表示的假设。它们不是——它们是数字的精确二进制(base-2)表示。您遇到的问题是您不能始终以十进制格式表示精确的二进制数 - 就像您不能以十进制格式表示 1/3 (.33333333...)。在某些时候,必须进行舍入。

          在您的示例中,当您表示 .1F 时会发生舍入(因为这不是一个可以用 base-2 精确表示的值)。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2019-03-15
            • 2018-01-10
            • 1970-01-01
            • 1970-01-01
            • 2020-07-02
            相关资源
            最近更新 更多