For loop 对于具有十进制增量的循环!=。5产生奇怪的结果 原意

For loop 对于具有十进制增量的循环!=。5产生奇怪的结果 原意,for-loop,floating-point,basic,c64,For Loop,Floating Point,Basic,C64,我刚刚找到我的老Commodore 64电脑,把它连接起来,并决定再次尝试学习基础知识。我刚刚完成了第3章,其中演示了一个简单的FOR循环: 10 FOR NB = 1 TO 10 STEP 1 20 PRINT NB, 30 NEXT NB 正如预期的那样,这将产生以下结果: 1 2 3 4 5 6 7 8 9 10 引入浮点数 步骤设置为1.0时,上述结果相同。但是,除0.5以外的其他数字会导致问题: 如

我刚刚找到我的老Commodore 64电脑,把它连接起来,并决定再次尝试学习基础知识。我刚刚完成了第3章,其中演示了一个简单的FOR循环:

10 FOR NB = 1 TO 10 STEP 1
20 PRINT NB,
30 NEXT NB
正如预期的那样,这将产生以下结果:

1       2       3       4
5       6       7       8
9       10
引入浮点数 步骤设置为1.0时,上述结果相同。但是,除0.5以外的其他数字会导致问题:

如果我将步长增量更改为.5或1以外的任何值,我会得到奇怪的浮点值,显然,浮点值越低,出现得越早。在第一次测试中,我将NB改为1到40

测试结果 对于NB=1到40,步骤6:1-31的正常结果,然后是31.6000001。为了看我是否会得到更高的奇怪结果,我将NB增加到100,然后看到奇怪的数字从42开始:41.2、41、8、42.4、42.999999、43.599999等等。 对于NB=1到40,步骤4:1-7.4的正常结果,然后是78000001,然后是正常结果8.2-22.6,然后是22.9999999、23.399999等。 对于NB=1到40,步骤2:1–6.2的正常结果,然后以6.399999 in.2的增量直到8.599999,然后从8.799998更改到9.999998,然后从10.2的正常结果。 对于NB=1到40,步骤1:1–3.6的正常结果,然后是3.699999等。 对于NB=1至40,第05步:正常结果为1–2.3,然后为2.3499999注额外数字,直到2.5999999,然后为2.65–2.7,然后为2.7499999等。 失效迭代次数 这些步骤在以下迭代中失败:

0.6增量在迭代时失败 52 31.6000001, 51-70可以, 那么71–87是0.0000001到小exmpl:42.999999, 那么88–103是进一步的一个减例:53.1999998, 然后进一步减少104起,例如:62.7999997。 0.4增量在迭代时失败 18, 19-55岁可以, 56–64是在−.9999999, 65就可以了, 66–84位于−.9999999, 85-100可以, 101-116为+0.0000001, 117以0.000002继续,以此类推。 0.2增量在迭代时失败 28时−.9999999, 47-107没问题, 108–140在+0.0000001时发生故障, 141以后的版本在+0.0000002时失败,依此类推 0.1增量在迭代时失败 28时−.9999999, 79-88行, 89–90在+0.00000001 sic时发生故障, 91-116行, 117–187在+0.0000001时失败, 188起在+0.0000002时失败,依此类推。 0.05增量在迭代中失败 28–33分−.00000001, 34-35岁可以, 36–68在以下位置失败:−0.00000001, 69-78可以, 79–92在+0.00000001时失败, 93–106在+0.00000002时发生故障, 107以后的版本在+0.00000003处失败,依此类推。 上述说明 为了记录在案,我增加了一个计数器以便于报告;因此,该程序如下所示:

05 NC = 1
10 FOR NB = 1 TO 100 STEP 0.05: REM 0.6, 0.4, 0.2, 0.1, 0.05
20 PRINT NC;":";NB,
25 NC = NC + 1
30 NEXT NB
主要问题
我怀疑问题在于如何将十进制转换为二进制,但奇怪的是,它在0.5个步骤中工作得非常好。是什么导致了这个错误,人们如何补救它,或者如何解释它?我的海军准将运行Basic v2。

我想,由于.5的倍数可以很容易地转换为base 2,所以它不会产生任何问题。我敢打赌,如果您尝试使用.25增量,它也会很好地工作。

我想,由于.5的倍数可以很容易地转换为基数2,因此它不会产生任何问题。我敢打赌,如果您尝试使用.25增量,它也会很好地工作。

欢迎来到疯狂、古怪、奇妙的浮点数世界。这不仅限于基本的。正如在Afrestor的回答中简要解释的那样,这是因为处理十进制数作为二进制数的精度。考虑如果你尝试用1/3增加,但是你的计算机只能处理十进制数字,只有小数点后两位数。它不能计算1/3,2/3,1,4/3,5/3,2,…它只能计算.33,.66,.99,1.32,1.65,1.98,…当您使用二进制浮点尝试用小数点计数时,也会发生同样的情况。这些数字略有偏差,误差随着情况的发展而增加。b您并不总是能立即看到错误,因为浮点输出的格式只有几个数字,没有显示整个值。@EricPostFischil我想这就是为什么我会出现明显随机出现的偏移量数字,然后会更正一段时间,经过足够多的迭代之后,最终似乎一直是错误的。欢迎来到疯狂、古怪、奇妙的浮点数世界的可能重复。这不仅限于基本的。正如在Afrestor的回答中简要解释的那样,这是因为处理十进制数作为二进制数的精度。考虑如果你尝试用1/3增加,但是你的计算机只能处理十进制数字,只有小数点后两位数。它不能计算1/3,2/3,1,4/3,5/3,2,…它只能计算.33,.66,.99,1.32,1.65,1.98,…当您使用二进制浮点尝试用小数点计数时,也会发生同样的情况。数字略有出入,
随着事情的发展,误差也会增加。b您并不总是能立即看到错误,因为浮点输出的格式只有几个数字,没有显示整个值。@EricPostFischil我想这就是为什么我会出现明显随机出现的偏移量数字,然后会更正一段时间,经过足够多的迭代之后,最终似乎一直是错误的。可能是C64的重复,但C64清楚地将整数与浮点数区分开来。在我的手册上。34ff,在变量下,我们解释了变量由两个字符区分,第一个字符是字母,第二个字符是浮点数、百分位数、整数或美元符号、字符串;此外,关于p。35它将整数限制为−32768–+32767,因此2⁶ 但是,字节我可能在这里错了。对于可以精确表示为“A/2^B”的整数A和B的合理分数,算术将是精确的。0.5、0.25、0.75、0.125、0.325、0.824…细微的挑剔,就整数值而言,这将是2^16位而不是字节。与C64的浮点单精度4字节相比,BASIC的后几代实现了双精度8字节,但这两个数字的内部存储格式甚至不同。我记得有一个CVDMBF函数,我写了转换从微软二进制格式到IEEE格式的双精度,例如。然后是不同类型的舍入。有趣的是,查一下银行家四舍五入。这是VB6在默认情况下决定采用的。银行家四舍五入是指四舍五入半美分的方法。通常情况下,0.5的值总是四舍五入到1,-0.5的值总是四舍五入到零最高整数值,但在银行家的四舍五入中,四舍五入的方向取决于小数点左边的数字是什么,奇数还是偶数。我想不起确切的公式,但它可能,例如,根据触发器的奇数或偶数,将3.5和4.5四舍五入到3,或相应地四舍五入到3和5。它被认为是一种更公平的银行取整系统。@CannedMan C64基本区分整数、整数和浮点仅用于存储。所有数学运算都使用浮点。任何数学运算之前的整数首先转换为浮点;仅当分配给整型变量时,结果才会转换为整数值;因此整数变量的速度很慢,但C64清楚地将整数与浮点数区分开来。在我的手册上。34ff,在变量下,我们解释了变量由两个字符区分,第一个字符是字母,第二个字符是浮点数、百分位数、整数或美元符号、字符串;此外,关于p。35它将整数限制为−32768–+32767,因此2⁶ 但是,字节我可能在这里错了。对于可以精确表示为“A/2^B”的整数A和B的合理分数,算术将是精确的。0.5、0.25、0.75、0.125、0.325、0.824…细微的挑剔,就整数值而言,这将是2^16位而不是字节。与C64的浮点单精度4字节相比,BASIC的后几代实现了双精度8字节,但这两个数字的内部存储格式甚至不同。我记得有一个CVDMBF函数,我写了转换从微软二进制格式到IEEE格式的双精度,例如。然后是不同类型的舍入。有趣的是,查一下银行家四舍五入。这是VB6在默认情况下决定采用的。银行家四舍五入是指四舍五入半美分的方法。通常情况下,0.5的值总是四舍五入到1,-0.5的值总是四舍五入到零最高整数值,但在银行家的四舍五入中,四舍五入的方向取决于小数点左边的数字是什么,奇数还是偶数。我想不起确切的公式,但它可能,例如,根据触发器的奇数或偶数,将3.5和4.5四舍五入到3,或相应地四舍五入到3和5。它被认为是一种更公平的银行取整系统。@CannedMan C64基本区分整数、整数和浮点仅用于存储。所有数学运算都使用浮点。任何数学运算之前的整数首先转换为浮点;仅当分配给整型变量时,结果才会转换为整数值;所以整数变量的速度很慢