c#浮点循环,意外结果

时间:2012-07-06 15:16:02

标签: c# for-loop floating-point

任何人都可以向我解释为什么这个程序:

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

舍入错误来自哪里?

7 个答案:

答案 0 :(得分:3)

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

答案 1 :(得分:3)

我确信这个问题之前一定是以某种形式提出过的,但我很快就找不到了。 :)

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

浮点数(无论如何像双打和浮点数一样,基数2浮点数)工作[0]的方法是将1/2的幂加起来得到你想要的。所以0.5只是1/2。 0.75是1/2 + 1/4,依此类推。

问题在于,你不能在这个二进制系统中代表0.1,如果没有2个越来越小的幂的无限流,那么计算机能做的最好就是存储一个非常接近但不是很接近0.1的数字。

通常你没有注意到这些差异,但它们存在,有时你可以让它们自己显现出来。有很多方法可以解决这些问题,你使用哪种方法很大程度上取决于你实际使用它的方式。

[0]略微手持式接近

答案 2 :(得分:2)

最大的问题是0.1无法用二进制表示,就像1 / 31 / 7无法用十进制表示一样。因此,由于计算机必须在某个时刻切断,因此会累积舍入错误。

尝试使用几乎任何编程语言执行0.1 + 0.7 == 0.8,结果会导致错误。

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

答案 3 :(得分:2)

这将解释有关浮点的所有内容: http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html

答案 4 :(得分:1)

舍入错误来自Float不是精确数据类型(转换为十进制)时的事实,它是一个近似值,注意C# Reference Float被指定为具有7位小数精度。< / p>

答案 5 :(得分:1)

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

请尝试使用Decimal。

答案 6 :(得分:1)

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

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