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

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

问题描述

我不确定这是否是一个错误,所以我想也许你们可能想看看.

问题出在这段代码上:

for i=0,1,.05 做打印(一)结尾

输出应该是:

<预><代码>0.05.1--剪断--.951

相反,输出是:

<预><代码>0.05.1--剪断--.95

while 循环也发生了同样的问题:

w = 0而 w <= 1 做打印(宽)w = w + .05结尾- 输出:0.05.1--剪断--.95

w 的值为 1,可以通过循环后的打印语句进行验证.

我已尽可能验证任何小于或等于 0.05 的步长都会产生此错误.任何高于 0.05 的步骤都应该没问题.我验证了 1/19 (0.052631579) 确实打印了 1.(显然,像 19.9 或 10.5 这样的十进制分母不会产生 [0,1] 包含的输出.)这是否有可能不是语言错误?解释器和常规 Lua 文件都会产生此错误.

解决方案

这是一个舍入问题.问题是 0.05 表示为浮点二进制数,并且它没有二进制的精确表示.在基数 2(二进制)中,它是一个重复的小数,类似于像基数 10 中的 1/3 这样的数字.重复相加时,四舍五入的结果是略大于 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+0.05+0.05+0.05+>打印(x)1>打印(1==x)错误的>打印(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>打印(0.05*20==1)真的

因此,您可以重写代码来说明

for i=0,20,1 做打印(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.

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

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