FOR〜NEXT loop is the most commonly used instruction in BASIC. The behavior of it is prescribed in the BASIC standards such as ANSI/ISO minimal BASIC, ANSI/ISO Full BASIC and ECMA BASIC. Knowing the precise behavior of FOR〜NEXT loop, we can make concise and reliable programs.
A FOR〜NEXT loop is written in the following form:
FOR control_var = initial_value TO limit STEP increment ……… NEXT control_var
limit and increment are evaluated before the repetition starts and stored in invisible variables.
When increment is a positive number, the repetition works as follows.
(1) Assigns initial_value to control_var.
(2) If control_var is greater then limit, the control goes to the next line of NEXT.
(3) When NEXT statement is executed, control_var is added increment and goes back ot (2).
When increment is a negative number, the magnitude relation in (2) is reversed.
When “STEP increment” is omitted, increment is regarded as 1.
When increment is a positive number, if initial_value is greater than limit, the repetition part is not executed and the FOR〜NEXT loop finishes. control_var remains to be initial_value.
The condition of exitting the repetition is that the value of the control variable is greater than the limit. Thus a FOR〜NEXT loop where the difference of the initial value and the limit is not a multiple of the increment can be allowed as fllows:
10 FOR i=0 TO 100 STEP 3 20 PRINT i 30 NEXT i
When the last time PRINT statement in line 20 is executed, the value of the varibale i is 99, and the value of i is 102 after exitting the loop.
小数を増分に指定する場合,誤差に注意が必要です。たとえば,
10 FOR x=0 TO PI STEP PI/6 20 PRINT x 30 NEXT x
で最後に出力されるのは, 2.6179938779915 で,3.141592…が出力されて終わると思っていると期待を裏切られます。というのは,この次のxの値は 3.1415926535898 で, 3.14159265358979よりわずかに大きくなるため,そこで繰り返しを抜けてしまうからです。
対策の一つは,限界を少し大きめに指定することで,
たとえば,
10 FOR x=0 TO PI+1E-10 STEP PI/6
とすると,最後の出力は3.1415926535898 となって,ほぼ期待通りになります。
もうひとつのやり方は,FOR文には整数しか使わないと決めて,
10 FOR i=0 TO 6 20 LET x=PI*i/6 30 PRINT x 40 NEXT i
のようにすることです。このやり方は誤差が累積することがないので正確さの点で優位です。
2進モード(および複素数モード)では,0.1のように,見かけ上,切りのよい小数も誤差を持ちます。たとえば,
10 OPTION ARITHMETIC NATIVE 20 FOR x=1 TO 2 STEP 0.1 30 PRINT x 40 NEXT x 50 END
を実行すると最後の出力は1.9になります。
増分と限界はプログラムからは見えない変数に保持されます。そのため,
10 LET s=0.1 20 FOR i=1 TO 10 STEP s 30 PRINT i,s 40 IF i=1 THEN LET s=1 50 NEXT i 60 END
を実行すると,40行でsの値を書き換えているにもかかわらず,増分はずっと0.1のままです。
また,
10 LET n=10 20 FOR i=1 TO n 30 PRINT i,n 40 IF i=4 THEN LET n=5 50 NEXT i 60 END
を実行すると,40行でnの値を書き換えているにもかかわらず,30行は10回実行されます。
10 FOR i=1 TO 100 20 PRINT i 30 IF i=20 THEN LET i=100 40 NEXT i
のように制御変数の値を書き換えると,繰り返しに影響を与えます。
内部副プログラムや内部関数定義で呼び出し元と同じ制御変数を用いる誤りはよくある失敗です。
例
10 FOR i=1 TO 10 20 CALL ss 30 NEXT i 40 SUB ss 50 FOR i=1 TO 10 60 PRINT i 70 NEXT i 80 END SUB 90 END
このプログラムで20行は1回実行されるのみです。なぜなら,内部副プログラムssの実行を終えた時点で変数 i の値が11になっているからです。
(この種の誤りを避ける手段は,(1) 別の変数名を用いる (2) 外部手続きを用いる (3) 拡張命令のLOCAL文を使う。これらのうち,最も確実なのは,外部手続きの利用です。)
EXIT FOR文は制御変数の値を変えません。また,BASICではFOR〜NEXTループを抜けても制御変数は有効な変数です。
したがって,制御変数の値と限界とを比べることで,EXIT FOR文を実行して繰り返しを抜けたのか,それとも最後までFOR〜NEXTの繰り返しを実行して抜けてきたのかを判別することができます。
ある自然数nが素数かどうかは,√nを超えない自然数で順に割ってみればわかります。除数をFOR〜NEXTで順に作って割り切れたら繰り返しを抜けることにしたら,FOR〜NEXTを抜けたところで制御変数の値を調べることで,約数が存在したのか否かを判定することができます。
100 INPUT n 110 FOR k=2 TO SQR(n) 120 IF MOD(n,k)=0 THEN EXIT FOR 130 NEXT k 140 IF k>SQR(n) THEN 150 PRINT "素数" 160 ELSE 170 PRINT "約数";k;"を持つ合成数" 180 END IF 190 END
少し詳しく書くと,
FOR v=始値 TO 限界 STEP 増分 (一連の文) NEXT v |
は,
LET own1=限界 LET own2=増分 LET v=始値 DO UNTIL (v - own1)*SGN(own2)>0 (一連の文) LET v=v+own2 LOOP |
で定義されています。
own1,own2は,翻訳時にFOR〜NEXT構文ごとに確保される変数で,プログラム上は表に現れない変数です。プログラムで直接的に操作する手段はありません。
例 JIS規格のBASIC(基本BASICを含む)では,次のプログラムの30行は11回実行され,100から110までが順に出力されます。
10 LET n=100 20 FOR n=n TO n+10 30 PRINT n 40 NEXT n 50 END
<Note>
own1,own2はFOR文の実行ごとに確保される変数ではないことに注意してください。FOR〜NEXTループ内からGOSUB文を用いてFOR〜NEXTの再帰呼び出しを行うと(制御変数の退避を正しく行ったとしても)正しく動作しません。
なお,Ver.7.2.0でFOR〜NEXTを内部手続き内に書いた場合は,own1,own2を内部手続きの局所変数として確保するように仕様を変更しました。JISとの整合性を確保するために,従来通り,常にプログラム単位の変数として確保するオプションも用意してあります。(内部手続きに書かれたFOR〜NEXTループから内部手続きの再帰呼び出しを行うときに,own1,own2がプログラム単位の変数であると,意図した通りに動作しないかも知れません)