For loop 对于具有十进制增量的循环!=。5产生奇怪的结果 原意
我刚刚找到我的老Commodore 64电脑,把它连接起来,并决定再次尝试学习基础知识。我刚刚完成了第3章,其中演示了一个简单的FOR循环: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以外的其他数字会导致问题: 如
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基本区分整数、整数和浮点仅用于存储。所有数学运算都使用浮点。任何数学运算之前的整数首先转换为浮点;仅当分配给整型变量时,结果才会转换为整数值;所以整数变量的速度很慢