在C#(.NET 3.5 SP1)下面的代码是我的机器上的无限循环:

for (float i = 0; i < float.MaxValue; i++) ;

它达到数16777216.0和16777216.0 + 1是评估为16777216.0。然而,在这一点:!I + 1 = I

这是一些疯狂。

我知道有在浮点数是如何存储的一些不准确度。和我读过整数比不能适当地存储为浮子更大2 ^ 24

还是上述代码中,应该是有效的在C#即使号码不能正确表示。

为什么它不工作?

您可以得到发生双相同,但它需要一个很长的时间。 9007199254740992.0是双重的极限。

有帮助吗?

解决方案

对,所以这个问题是为了增加一个浮子,这将有可能成为

16777217.0

碰巧,这是在用于radix的边界,并且不能准确地为float表示。 (可用的下一个最高值是16777218.0

所以,舍入到最接近的可表示浮子

16777216.0

让我这样说:

由于你有一个浮动的精度量,必须由高和更高数量递增的。

修改

确定,这是困难的一点点地解释,但尝试:

float f = float.MaxValue;
f -= 1.0f;
Debug.Assert(f == float.MaxValue);

这将运行得很好,因为在那个值,为了表示1.0f的差异,就需要精度超过128位。浮子仅具有32位。

<强> EDIT2

通过我的计算,至少128个二进制位的无符号是必要的。

log(3.40282347E+38) * log(10) / log(2) = 128

作为解决你的问题,你可以通过两个128位的数字环路。然而,这将需要至少十年来完成。

其他提示

想象例如,一个浮点数被至多2个显著十进制数字表示,以及一个指数:在这种情况下,可以计算从0到99完全相同。接下来将是100,而是因为你只能有一个会被存储为“1.0倍10 2的幂” 2个显著数字。添加一个到会...什么?

目前最好的,这将是101作为中间结果,这实际上将被存储(经由其丢弃微不足道第三位的舍入误差)为“1.0倍10至2的幂”一次。

要了解什么错你将不得不阅读浮点IEEE标准

让我们来看看浮点的编号为第二:

一个浮点数被分成两个部分(OK 3,但忽略了第二符号位)。

您有一个指数和一个尾数。像这样:

smmmmmmmmeeeeeee

请注意:这不是acurate的比特数,但它给你发生了什么事的总体思路

要弄清楚什么号码,你有我们做如下的计算:

mmmmmm * 2^(eeeeee) * (-1)^s

那么,什么是float.MaxValue将是?那么你将有最大可能的尾数和尽可能大的指数。让我们假设这看起来是这样的:

01111111111111111

在现实中,我们定义NAN和+-INF和几个其他公约,却忽略了他们第二个,因为他们是你的问题不相关的。

所以,当你9.9999*2^99 + 1会发生什么?好了,你没有足够的显著数字,加1,因为它得到四舍五入到相同数量的结果。在的单浮点精度的情况下在该+1开始被向下舍入点碰巧16777216.0

它无关溢出,或正在接近最大值。为16777216.0的浮点值有16777216的二进制表示然后加1,所以它应该是16777217.0,不同之处在于16777217.0二进制表示是16777216!因此,它实际上并没有得到增加或至少增量不会做你期望的。

下面是由乔恩斯基特写入一个类,说明这一点:

DoubleConverter.cs

尝试此代码与它

double d1 = 16777217.0;
Console.WriteLine(DoubleConverter.ToExactString(d1));

float f1 = 16777216.0f;
Console.WriteLine(DoubleConverter.ToExactString(f1));

float f2 = 16777217.0f;
Console.WriteLine(DoubleConverter.ToExactString(f2));

注意的16777216.0的内部表示如何为相同16777217.0 !!

当我接近float.MaxValue具有ⅰ刚刚低于该值的迭代。下一次迭代增加了我,但不能持有数量比float.MaxValue更大。因此,它包含一个值小得多,并再次开始循环。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top