奇怪的循环问题 [英] Strange for loop problem

查看:195
本文介绍了奇怪的循环问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我不确定这是不是一个bug,所以我想也许你们可能想看看。



问题出在这个代码:

  for i = 0,1,.05 do 
print(i)
end

输出应该是:

  0 
.05
.1
--snip--
.95
1



相反,输出是:

$ p $ 0
.05
.1
--snip--
.95

while循环发生同样的问题:

  w = 0 
while w < = 1 do
print(w)
w = w + .05
end
- 输出:
0
.05
.1
--snip--
.95

w的值是1 ,这可以通过循环后的print语句来验证。



我已经尽可能地验证了任何小于或等于.05的步骤都会产生这个错误。上面的任何步骤.05应该没问题。我证实了1/19(0.052631579)确实打印出了1(显然,像19.9或10.5这样的小数分母不会产生[0,1]的输出)。是否有可能这不是语言的错误?解释器和一个常规的L​​ua文件都会产生这个错误。 解决方案

这是一个舍入问题。问题是,0.05被表示为一个浮点二进制数,并没有在二进制中的确切表示。在基数2(二进制)中,它是一个重复的十进制数,类似于基数为10的数字。当反复添加时,舍入结果的数字略大于1.它只是非常略大于1 ,所以如果你打印出来,它显示1作为输出,但它不完全是1。 x = 0.05 + 0.05 + 0.05 + 0.05 + 0.05 + 0.05 + 0.05 + 0.05 + 0.05 + 0.05 + 0.05 + 0.05 + 0.05 + 0.05 + 0.05 + 0.05 + 0.05 + 0.05 + 0.05 + 0.05
> print(x)
1
> print(1 == x)
false
> print(x-1)
2.2204460492503e-16

如你所见,虽然真的接近1,但它实际上稍微多一些。

当我们有重复分数时,类似的情况会出现在小数点。如果我们将1/3 + 1/3 + 1/3加起来,但是我们不得不四舍五入来处理,我们会加上0.333333 + 0.333333 + 0.333333,得到0.999999这实际上不是1.这是一个二进制数学的类似情况。 1/20不能用二进制精确表示。



请注意,乘法的舍入略有不同,因此

 >打印(0.05 * 20-1)
0
> print(0.05 * 20 == 1)
true

因此,您可以重写你的代码要说:

$ p $ for i = 0,20,1 do
print(i * 0.05)
结束

它会正常工作。一般来说,建议不要使用浮点数(即带小数点的数字)来控制循环。


I'm not sure if this is a bug or not, so I thought that maybe you folks might want to take a look.

The problem lies with this code:

for i=0,1,.05 do
    print(i)
end

The output should be:

0
.05
.1
--snip--
.95
1

Instead, the output is:

0
.05
.1
--snip--
.95

This same problem happened with a while loop:

w = 0
while w <= 1 do
    print(w)
    w = w + .05
end
--output:
0
.05
.1
--snip--
.95

The value of w is 1, which can be verified by a print statement after the loop.

I have verified as much as possible that any step that is less than or equal .05 will produce this error. Any step above .05 should be fine. I verified that 1/19 (0.052631579) does print a 1. (Obviously, a decimal denominator like 19.9 or 10.5 will not produce output from [0,1] inclusive.) Is there a possibility that this is not an error of the language? Both the interpreter and a regular Lua file produce this error.

解决方案

This is a rounding problem. The issue is that 0.05 is represented as a floating point binary number, and it does not have an exact representation in binary. In base 2 (binary), it is a repeating decimal similar to numbers like 1/3 in base 10. When added repeatedly, the rounding results in a number which is slightly more than 1. It is only very, very slightly more than 1, so if you print it out, it shows 1 as the output, but it is not exactly 1.

> x=0.05+0.05+0.05+0.05+0.05+0.05+0.05+0.05+0.05+0.05+0.05+0.05+0.05+0.05+0.05+0.05+0.05+0.05+0.05+0.05
> print(x)
1
> print(1==x)
false
> print(x-1)
2.2204460492503e-16

So, as you can see, although really close to 1, it is actually slightly more.

A similar situation can come up in decimal when we have repeating fractions. If we were to add together 1/3 + 1/3 + 1/3, but we had to round to six digits to work with, we would add 0.333333 + 0.333333 + 0.333333 and get 0.999999 which is not actually 1. This is an analogous case for binary math. 1/20 cannot be precisely represented in binary.

Note that the rounding is slightly different for multiplication so

> print(0.05*20-1)
0
> print(0.05*20==1)
true

As a result, you could rewrite your code to say

for i=0,20,1 do
    print(i*0.05)
end

And it would work correctly. In general, it's advisable not to use floating point numbers (that is, numbers with decimal points) for controlling loops when it can be avoided.

这篇关于奇怪的循环问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆