2011-10-05 90 views
1

我是通过一个浮动像这样的所有可能值试图循环:任何人都可以向我解释这个浮点奇怪吗?

float i = 0.0F; 
float epsilon = float.Epsilon; 
while (i != float.MaxValue) { 
    i += epsilon; 
} 

但到达值2.3509887E-38F之后不再增加。

float init = 2.3509887E-38F; 
float f = (init + float.Epsilon); 
Console.WriteLine(f == init); 

我只是好奇,任何人都可以解释为什么?

所以,我可以在四舍五入错误之前将一个16777216的浮点数添加到epsilon,并且该数字看起来非常熟悉(2^24)。

+0

你的第二个代码输出'false' ... –

+0

看到这个类似的问题,它应该给你一些见解:) http://stackoverflow.com/questions/4251298/why-float-maxvalue-float-maxvalue-1-确实返回true – Martin

+0

Blimey,这将需要一段时间。 –

回答

3

这里有很多非常毛茸茸的想法。浮点数不是“不精确”的。没有“可能”。这是一个确定性系统,就像计算机上的其他任何东西一样。

不要通过查看十进制表示来分析发生了什么。如果您以二进制或十六进制查看这些数字,此行为的来源就显而易见了。让我们用二进制:

float.Epsilon is b1.0 x 2^-149 
2.3509887E-38 is b1.0 x 2^-125 

如果加上这两个数字加在一起,无限精确的(未四舍五入)之和为:

b1.000 0000 0000 0000 0000 0000 1 x 2^-125 

注意,这笔款项的有效数为25个位宽(我将二进制数字分组为四个组,以使它们更容易计数)。这意味着它不能以单精度表示,所以这个总和的结果是这个值不是,而是这个值四舍五入到可以代表的关闭float。两个最接近的可表示数字是:

b1.000 0000 0000 0000 0000 0000 x 2^-125 
b1.000 0000 0000 0000 0000 0001 x 2^-125 

我们的号码正好在它们之间。由于您尚未在您的程序中设置舍入模式,因此我们处于默认舍入模式,称为“舍入到最近,与偶数相关”。因为这两个选项同样接近,所以通过选择最低位为零的那个来打破平局。因此,2^-125 + 2^-149四舍五入为2^-125,这就是“停止增长”的原因。

+0

当某些东西四舍五入时,它几乎是根据定义*不精确*。你甚至可以通过参考“无限精确的(未被理解的)总和”来确定它的意义。一旦四舍五入,就不再精确。 –

+0

你所说的答案绝对比我的更精确。 –

+0

@AndrewBarber:圆整的结果不等于通常所说的“无限精确”(实数)结果。但是,它恰恰是*浮点算术结果。两者都是精确的数字;只是算术系统不同 - 如果我在同一个硬件上反复添加这两个浮点数,每次都会得到相同的结果。这是精确的。 –

4

浮点数不准确;它们只能保存如此多的有效数字,并且如果需要存储其当前值,将忽略被认为“太微不足道”的值。

关键是名称的“浮动”部分;该变量让'point'浮动到需要存储值的地方,这意味着浮点变量可以存储非常大或非常精确的值,因为它可以'移动'它所需的点。但它通常不能存储既大又精确的值。

但'大'简化它太多;任何具有大量显着数值的数字都不能存储太多精确的数值。由于您正在尝试添加非常小的内容,因此很可能会失去快速处理此类精度的能力。

如果您记下了一个非常大的值,您可能会发现即使添加/减少整数仍然不会导致更改。

编辑:见斯蒂芬佳能的答案更准确答案也。 ;)

0

由于epsilon(1.401298E-45)与2.3509887E-38F相比太小,将两者加在一起时,float中没有足够的位来精确地表示总和,并且整个eps丢失。

计算机上的浮点数学算法并不适用于我们在学校教数学的方式,因为这里的数字用有限的位数来表示,这将数学限制在某个范围的值(最小值和最大值)和某些有限的精度(尾数位数)。

相关问题