C#漂浮死循环

由于碰到for循环陷入死循环问题,所以查了一下,主要是存储方式的问题,所以为了避免死循环,使用int或者是较小的float。

转自:http://www.55228885.com/wAD9WZnp.html

C#漂浮死循环

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

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

它达到了数16777216.0和16777216.0 + 1的结果为16777216.0。 然而在这一点上:i + 1的=岛

这是一些疯狂。

我知道有如何浮点数存储一些误差。 我读过整数更大的2 ^ 24比不能正确地存储为浮动。

不过上面的代码,应该在C#有效的,即使在一些不能正确代表。

为什么它不工作?

你可以得到相同的情况发生,以双倍的,但它需要一个很长的时间。 9007199254740992.0是极限了一倍。

--------------解决方案-------------

右,所以问题是,为了添加一个到浮子,那就要成为

16777217.0 

它只是恰巧,这是在为基数的边界,不能完全作为一个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 

在现实中我们定义楠+-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的迭代有我只是低于此值。 在下一次迭代增加为i,但它不能保持大于float.MaxValue更大一些。 因此,保持一个值要小得多,并且再次开始循环。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值