-1

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

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

舍入误差从何而来?

4

7 回答 7

3

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

于 2012-07-06T15:17:57.883 回答
3

我敢肯定这个问题以前一定是以某种形式提出过的,但我无法在任何地方快速找到它。:)

答案归结为浮点数的表示方式。您可以通过维基百科了解技术细节,但简单地说,十进制数不一定具有精确的浮点表示......

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

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

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

[0] 以稍微接近的方式

于 2012-07-06T15:24:47.997 回答
2

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

尝试0.1 + 0.7 == 0.8用几乎任何编程语言做,结果你会得到错误的。

在 C# 中为了解决这个问题,使用decimal类型来获得更好的精度。

于 2012-07-06T15:20:14.937 回答
2

这将解释关于浮点的一切:http: //docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html

于 2012-07-06T15:28:54.880 回答
1

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

于 2012-07-06T15:19:17.083 回答
1

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

尝试使用 Decimal 代替。

于 2012-07-06T15:19:29.297 回答
1

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

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

于 2012-07-06T15:22:54.413 回答