3 アルゴリズムの記述

3.1 IF 〜 END IF構文とIF文

3.1.1 IF 〜 ELSE 〜 END IF

例25 係数a,b,cを入力すると2次方程式ax2+bx+c=0の解を表示するプログラム

10 INPUT a,b,c
20 LET D=b^2-4*a*c
30 IF D>=0 THEN
40    PRINT (-b-SQR(D))/(2*a), (-b+SQR(D))/(2*a)
50 ELSE
60    PRINT "解なし"
70 END IF
80 END

このプログラムは,判別式D=b2-4ac の値によって処理を分けています。
D≧0のときには解の公式を用いて2つの解を計算して表示し,そうでないときには,「解なし」と表示します。
不等号「≧」は,BASICでは「>=」で代用します。
このように,ある条件が成立するときは〜を実行し,そうでないとき〜を実行する処理を記述するのに
IF 〜 ELSE 〜 END IFを用います。この構文は,次の形式で記述します。

IF 条件 THEN

ELSE

END IF
〜の部分には複数の文を書くことができます。FOR〜NEXT構文やIF〜END IF構文のように複数行で構成される命令を書くこともできます。
なお,条件が成立しないときに実行すべき文がないときは,ELSEを省略して書くことができます。

3.1.2 IF 〜 ELSEIF 〜 ELSE 〜 END IF

例25ではD=0のとき解が2個表示されてしまいます。D=0のときの処理を別扱いにするためには,たとえば,

100 INPUT a,b,c
110 LET D=b^2-4*a*c
120 IF D>0 THEN
130    PRINT (-b-SQR(D))/(2*a), (-b+SQR(D))/(2*a)
140 ELSE
150    IF D=0 THEN
160       PRINT -b/(2*a)
170    ELSE
180       PRINT "解なし"
190    END IF
200 END IF
210 END

のようにすればよいのですが,これと同じことを次のように書くことができます。

例26

100 INPUT a,b,c
110 LET D=b^2-4*a*c
120 IF D>0 THEN
130    PRINT (-b-SQR(D))/(2*a), (-b+SQR(D))/(2*a)
140 ELSEIF D=0 THEN
150    PRINT -b/(2*a)
160 ELSE
170    PRINT "解なし"
180 END IF
190 END

3.1.3 IF文

例25のプログラムを

10 INPUT a,b,c 
20 LET D=b^2-4*a*c
30 IF D>=0 THEN PRINT (-b-SQR(D))/(2*a), (-b+SQR(D))/(2*a) ELSE PRINT "解なし"
40 END

と書くことができます。このように,条件が成立するとき,成立しないときに実行する文がどちらも一つであり,それらがともに単純実行文と呼ばれる種類の文である場合には,
IF 条件 THEN 単純実行文 ELSE 単純実行文
の形のIF文が利用できます。LET文,INPUT文,PRINT文,SET文,PLOT文,RANDOMIZE文などは単純実行文です。しかし,IF文は単純実行文ではありません。

なお,条件が成立しないときに実行する文がない場合には,
IF 条件 THEN 単純実行文
の形のIF文が使えます。たとえば,D<0のとき「解なし」と表示する必要がなければ,

10 INPUT a,b,c
20 LET D=b^2-4*a*c
30 IF D>=0 THEN PRINT (-b-SQR(D))/(2*a), (-b+SQR(D))/(2*a)
40 END

とします。

3.1.4 条件の書き方

不等式 a≦b,a≧bは,それぞれ,a<=b,a>=bのように書きます。また,aとbとが等しくないこと(a≠b)は,a<>bと書きます。
AND,OR,NOTと括弧を用いて複雑な条件を記述することができます。
たとえば,「p かつ q」という条件をBASICでは p AND q と書きます。また,「p またはq」をBASICでは p OR qと書きます。
否定を表すNOTは,否定対象の直前に書きます。AND,OR,NOTが混じった条件を書いたときには,NOTが最も優先します。ANDとORとではANDが優先します。優先順位を変更したいときは括弧を用いることができます。
なお,数学では「a<x かつ x<b」のことをa<x<b と書きますが,BASICではこういう書き方はできません。

例 27 3または8で割り切れる3桁の自然数の総和を求めるプログラム

10 LET t=0
20 FOR n=100 TO 999
30    IF MOD(n,3)=0 OR MOD(n,8)=0 THEN
40       LET t=t+n
50    END IF
60 NEXT n
70 PRINT t
80 END

3.1.5 ピタゴラス数

x2+y2=z2となる3整数x,y,zをピタゴラス数といいます。ピタゴラス数を系統的に探すのには,x,yの値を順に変化させてz = SQR(x^2+y^2) が整数となるときのx,y,zを出力するようなプログラムを作ればいいでしょう。zが整数であるかどうかは,INT(z)がzと一致するかどうか調べればわかります。次のプログラムは,1≦x≦y≦100の範囲でピタゴラス数を探します。

例28

10 FOR x=1 TO 100
20    FOR y=x TO 100
30       LET z=SQR(x^2+y^2)
40       IF INT(z)=z THEN PRINT x,y,z
50    NEXT y
60 NEXT x
70 END

[Note] 上のプログラムは,N88-BASICのような古いタイプのBASICでも動作するでしょう。しかし,正しい結果は得られないかも知れません。JIS Full BASICでは,べき乗や平方根などの計算で,真の値が有効数字の桁数以下の十進数で表現できる場合には真の値が得られることになっているので,上のプログラムで正しい結果が得られます。

3.2 DO〜LOOP

3.2.1 DO〜LOOP

DO文とLOOP文は対にして用いられ,繰り返しの処理を記述するのに用いられます。

例29 無限ループ

10 LET A=0
20 DO
30    LET A=A+1
40    PRINT A
50 LOOP
60 END

DO〜LOOPの構文を書くと,DO文とLOOPの間に書かれた文が繰り返し実行されます。上の例では30行と40行が繰り返し実行されます。

[補足] 上のプログラムを実行したときは, をクリックするか,実行メニューから中断を選んで実行を打ち切ってください。

3.2.2 DO WHILE〜LOOP

条件が成立する間,繰り返しを実行する構文です。

例30

10 LET A=0
20 DO WHILE A<100
30    LET A=A+1
40    PRINT A
50 LOOP
60 END

例29の20行を修正して上のようにすると,Aの値が100になると繰り返しをやめるようになります。
DO WHILE 〜 LOOPは次の形式で書きます。この構文の動作を流れ図で表すと図のようになります。

DO WHILE 条件
LOOP

この構文では繰り返すべき処理を実行する前に条件を調べますから,最初から条件が成立しない場合には,1回も繰り返しを実行しません。たとえば,例30 で20行を
20 DO WHILE A<0
に変えると30行,40行は1回も実行されません。

3.2.3 DO UNTIL 〜 LOOP

DO WHILE 〜 LOOPは条件が成立する間,繰り返しを実行する構文ですが,DO UNTIL 〜 LOOPは,繰り返しを終了する条件を指定して繰り返しを実行させる構文です。

例31

10 LET A=0
20 DO UNTIL A>=100
30    LET A=A+1
40    PRINT A
50 LOOP
60 END

例31は例30とまったく同じ意味です。一般に,条件の否定を利用すれば,DO WHILE 〜 LOOPとDO UNTIL 〜 LOOPは相互に書き換えが可能です。UNTIL p はWHILE NOT pと同じです。どちらを用いるかは,プログラムを書く人がどちらを向いて思考しているかの相違によります。

3.2.4 素因数分解

DO〜LOOPを利用して入力された自然数を素因数分解するプログラムを作ることができます。変数nに分解すべき自然数を入力するものとします。まず,最初にnが2で割れるかどうか調べ,割れるときは2を出力してnを2で割ったもので置き換えます。これをnが2で割り切れる間,繰り返し実行します。nが2で割れなくなったら割る数を3にして同様のことを繰り返します。次は割る数を5にして同様のことを繰り返せばよいのですが,「次の素数」をコンピュータに答えさせるのは難しいので,割る数は単に1を加算していくだけにします。すると,割る数3の次は割る数4になるのですが,それでも不都合はありません。なぜかというと,すでに2で割れるだけ割ってあるからです。

例32 素因数分解

110 INPUT n
120 LET f=2
130 DO UNTIL n=1
140    DO WHILE MOD(n,f)=0
150       PRINT f;
160       LET n=n/f
170    LOOP
180    LET f=f+1
190 LOOP
200 END

変数fは割る数(因数,factor)を表します。120行で最初の割る数2をセットしています。140行から170行までの繰り返しでfで割れる間,割ります。割れなくなると(180行),fは1加算されます。これを130行のDO文と190行のLOOP文とで繰り返すのですが,いつか繰り返しを止めなければなりません。その条件は,nからすべての因数を取り尽くしたときですから,n=1になります。それが,130行に書かれた条件です。

3.2.5 EXIT DO

EXIT DO文は,DO〜LOOPの繰り返しを終了してLOOP文の次の行に制御を移す命令です。DO WHILE 〜 LOOPやDO UNTIL 〜 LOOPは繰り返しの中身を実行する前にそれを実行すべきかどうか判断します。しかし,その位置では繰り返しを継続すべきかどうかの判断ができない場合があります。そのような場合,EXIT DO文を用います。
次のプログラムは,正しい答えを入力するまで繰り返し入力を要求します。この場合,入力してからでないと正しいかどうかの判断のしようがありません。

例33

10 PRINT "2×3=?"
20 DO
30   INPUT n
40   IF n=2*3 THEN EXIT DO
50   PRINT "残念,もう一度"
60 LOOP
70 PRINT "正解!"
80 END

例33の処理の流れを図に表すと次のようになります。

3.2.6 基底の変換

正の整数nを入力するとnを2進法で表示するプログラムを作ります。
たとえば,n =11とすると
11=1×23+0×22+1×2+1
ですから,11を2進法で表すと1011です。これを下位の桁から順に求めたいときは,次のようにします。

2)11 ・・・1
2) 5 ・・・1
2) 2 ・・・0
2) 1 ・・・1
0

整数aを整数bで割ったときの商をINT(a/b),余りをMOD(a,b)で求められるので,次のプログラムが得られます。

例34

10 INPUT n
20 DO
30    LET q=INT(n/2)
40    LET r=MOD(n,2)
50    PRINT r
60    IF q=0 THEN EXIT DO
70    LET n=q
80 LOOP
90 END

3.2.7 ユークリッドの互除法

2つの正の整数a,bに対して,a,bの最大公約数をgcd(a,b)で表すことにすると,次の性質が成り立ちます。
aをbで割ったときの余りをrとするとき,
  r = 0のとき,gcd(a,b) = b
  r≠0のとき,gcd(a,b) = gcd(b,r)
この性質を繰り返し利用し,次のようにすると,2つの整数の最大公約数を求めることができます。これをユークリッドの互除法といいます。
  aをbで割り,余りをrとする。
  r=0であれば,bが最大公約数である。
  r>0であれば,b,rを新たなa,bとしてこの操作を再度実行する。
この操作は,繰り返しのたびにbの値が小さくなっていくので,何回かの繰り返しの後,必ず終了します。

例35 ユークリッドの互除法により最大公約数を求める

10 INPUT a,b
20 DO
30    LET r=MOD(a,b)
40    IF r=0 THEN EXIT DO
50    LET a=b
60    LET b=r
70 LOOP
80 PRINT b
90 END

繰り返し処理の最後のところで,b,rの値を次のa,bの値とするために50行,60行に示すような順に代入文を用いることに注意してください。

3.3 配列

3.3.1 DIM文

プログラムのはじめに
DIM A(10)
と書くと,A(1),A(2),A(3),A(4),A(5),A(6),A(7),A(8),A(9),A(10)の計10個の変数が用意されます。A(1),A(2),A(3),…,A(10)は,それぞれ,普通の変数として使えます。このとき,この10個の変数をまとめて配列といって,個々の変数は添字付き変数といいます。そして,括弧内を添字(そえじ)といいます。

10 DIM A(10)
20 LET A(4)=15
30 PRINT A(4)
40 END

DIM文では,配列名と添字の上限を上のような形に書きます。配列名の付け方は普通の変数と同じです。添字の上限には10,20のような定数のみを書くことができます。

[Note]
配列の扱いは旧規格のJIS 基本BASICから変更されています。特に,配列の添字が1から始まることに注意してください。

添字付き変数では,添字に変数を含む式を書くことができます。たとえば,

10 DIM B(4)
20 LET i=3
30 LET B(i)=17
40 PRINT B(i)
50 END

この機能を利用すると,処理の対象となる変数をプログラムのなかで選ぶことが可能になります。BASICでは,B1,B2,B3のような変数名を使うこともできます。しかし,この場合には1, 2, 3の数字の部分は変数名の一部になっていますから,プログラムで番号を指定してB1,B2, B3のうちのいずれかを選ぶことはできません。

例 36 フィボナッチ数列

フィボナッチ数列 { fn } は,
  f1=1, f2=1, fn = fn-1+fn-2 (n = 3, 4, 5, …)
で定義される数列です。配列を利用してフィボナッチ数列のはじめの20項を求めるプログラムを書くと,次のようになります。

100 DIM f(20)
110 LET f(1)=1
120 LET f(2)=1
130 FOR i=3 TO 20
140    LET f(i)=f(i-1)+f(i-2)
150 NEXT i
160 FOR i=1 TO 20
170    PRINT i,f(i)
180 NEXT i
190 END

3.3.2 分布表を作る

配列は分布表を作るのに利用できます。ここでは,例として100点満点の試験の結果を10点刻みで分布を調べるプログラムを作成します。 m(0)からm(10)までの11個の添字付き変数を用意し,0点から9点までの人数をm(0),10点から19点までの人数をm(1),20点から29点までの人数をm(2),…,で表すことにします。 m(0)からm(10)での11個の添字付き変数が使えるようにするために

  DIM m(0 TO 10)

のようなDIM文をプログラムのはじめに書きます。 そして,

  MAT m=ZER

を実行し,配列mの全要素に0(zero)を代入しておきます。数値を入力すると,どのランクに属するかを表す指標iを計算し,その指標が示す添字付き変数に1を加算します。 すべての数値が入力されたら,負の数を入力することにします。

[Note] MATは,matrix(行列)のはじめの3文字をとったもので,行列演算命令の意味です。ZERはzeroのはじめの3文字です。

例37

100 DIM m(0 TO 10)
110 MAT m=ZER
120 DO
130    INPUT n
140    IF n<0 THEN EXIT DO  
150    LET i=INT(n/10)
160    LET m(i)=m(i)+1
170 LOOP
180 FOR i=0 TO 10
190    PRINT i*10;"〜";i*10+9,m(i)
200 NEXT i   
210 END

例38 10個のさいころを振るときの目の数の和を求めるシミュレーションを10000回繰り返し,その結果を集計してヒストグラムに表示するプログラム。

100 DIM A(10 TO 60)
110 MAT A=ZER
120 FOR k=1 TO 10000
130    LET t=0
140    FOR n=1 TO 10
150       LET t=t+INT(RND*6+1)
160    NEXT n
170    LET A(t)=A(t)+1
180 NEXT k
190 SET WINDOW 9,61,0,1000
200 FOR t=10 TO 60
210    PLOT LINES: t-0.5,A(t); t+0.5,A(t);
220 NEXT t
230 END



目の数の和は10以上60以下になるので,添字の範囲を10から60までにした配列Aを用意し,度数分布を求めています。

3.3.3 エラトステネスのふるい

整数の集合から合成数を順序よく取り除き,素数のみを残す方法で素数の集合を得ることができます。この手法は「エラトステネスのふるい」として古くから知られたものです。
2以上の整数を順に書き並べた表を用意し,n=2,3,4,…について,nの倍数であるような合成数n2, (n+1)n, (n+2)n, … に印をつけると,最後に残るのは素数です。
2から1000までの添字のついた配列sを用意し,添字付き変数s(n)で整数nを表します。そして,整数nに印がついていることをs(n)=1,印がついていないことをs(n)=0で表現します。

例 39

100 DIM s(2 TO 1000)
110 MAT s=ZER
120 FOR n=2 TO 1000
130    IF s(n)=0 THEN
140       PRINT n
150       FOR  k=n^2 TO 1000 STEP n
160          LET s(k)=1
170       NEXT k
180    END IF
190 NEXT n
200 END

nより小さいすべてのk(ただし2以上)について,kの倍数すべてに印をつける処理が終わっていれば,nに印がないことからnは素数であるという判断が下せます。この性質を利用して手順を合理化し,120〜190行のFOR〜NEXTループですべてを処理しています。
150〜170行のFOR〜NEXTでnの倍数に印をつけています。kの値をn2から順にnずつ増加させていくのではkの値が1000にならないことがありますが,FOR〜NEXT構文の性質からkの値が1000を超えたとき繰り返しを終了するのでこれで問題なく動作します。

3.3.4 配列宣言

配列には2次元,3次元のものも使えます。たとえば,DIM A(2,3) と書くと,A(1,1),A(1,2),A(1,3),A(2,1),A(2,2),A(2,3)の6個の添字付き変数が用意されます。
DIM文では,複数の配列をまとめて宣言することができます。その場合,各配列宣言はコンマで区切って書きます。たとえば,

  DIM A(4),B(10),C(20)

のように書きます。
Full BASICでは,配列の添字は1から始まるものと考えています。配列の添字が0から始まるようにしたいときは,最初の配列宣言を書く行よりも上の行にOPTION BASE 0と書きます。すると,すべての配列で添字の下限が0になります。

10 OPTION BASE 0
20 DIM A(4)
30 LET A(0)=7
40 MAT PRINT A
50 END

添字の下限を1または0以外の値にしたい場合や,配列ごとに異なる値にしたい場合には次の例に示すような構文を用いることもできます。

 DIM A(-4 TO 5),B(0 TO 2, 1 TO 3)

この配列宣言でA(-4)からA(5)までの10個の添字付き変数と,B(0,1)からB(2,3)までの9の添字付き変数が用意されます。

3.3.5 2項係数(パスカルの三角形)

2次元配列を利用してパスカルの三角形,すなわち,組合せの数nCrの表を作ってみましょう。nCrは,次の漸化式を用いて計算することができます。
r = 0 または r = n のとき nCr=1
0<rn のとき nCr = n-1Cr-1n-1Cr

例40

100 DIM C(1 TO 10, 0 TO 10)
110 MAT C=ZER
120 FOR n=1 TO 10
130    FOR r=0 TO n
140       IF r=0 OR r=n THEN
150          LET C(n,r)=1
160       ELSE
170          LET C(n,r)=C(n-1,r-1)+C(n-1,r)

180       END IF
190    NEXT r
200 NEXT n
210 MAT PRINT C;
220 END

3.3.6 MAT文

BASICは配列を処理するための便利な機能を用意しています。たとえば,MAT INPUT文とMAT PRINT文を用いると配列入出力が簡単になります。

例41

10 DIM A(5)
20 MAT INPUT A
30 MAT PRINT A
40 END

MAT INPUT文は,配列に数値をまとめて入力します。20行のMAT INPUT文の実行時には5個の数値をコンマで区切って入力してください。MAT PRINT文は,配列に属するすべての添字付き変数の値をまとめて出力します。なお,
30 MAT PRINT A;
のように配列名に続けてセミコロンを書いておくと,数値が詰めて出力されます。

MAT READ文はDATA文から配列に数値を代入します。 DATA文には必要な個数だけの数値をコンマで区切って書いておきます。テスト段階のプログラムなどで毎回同じデータを入力したいとき便利です。

例42 最小値を求める

10 DIM A(10)
20 DATA 45,61,73,91,43,12,65,34,96,12
30 MAT READ A
40 LET k=1
50 FOR i=2 TO 10
60    IF a(i)<a(k) THEN LET k=i
70 NEXT i
80 PRINT a(k)
90 END

3.3.7 整列(選択ソート)

10個の数値を入力すると大きさの順に並べ替えて出力するプログラムを作ります。
10個の数値はa(1)からa(10)までの10個の添字付き変数に入力するものとします。まず,a(1)からa(10)までの数値のうちで最小のものをa(1)と交換します。すると,a(1)が一番小さい数になります。次に,a(2)からa(10)までのうちで最小のものをa(2)と交換します。すると,a(2)に2番目に小さい数が入ります。以下,同様に,
FOR i=1 TO 9
a(i)からa(10)までのうちで最小のものをa(i)と交換する
NEXT i
を実行すれば,配列aには数値が小さい順に並べ替えられて入ることになります。

例43

100 DIM a(10)
110 MAT INPUT a
120 FOR i=1 TO 9
130    LET k=i                   ! kは最小値の番号
140    FOR j=i+1 TO 10
150       IF a(j)<a(k) THEN LET k=j
160    NEXT j
170    LET t=a(i)                    ! tを作業用の変数として用いて
180    LET a(i)=a(k)                 ! a(k)とa(i)の値を交換する
190    LET a(k)=t
200 NEXT i
210 MAT PRINT a;
220 END

130〜160行はa(i)〜a(10)の最小値の番号を変数kに取得する処理です。170〜190行ではtを作業用の変数として利用してa(i)の値とa(k)の値とを交換しています。
! 以降は行末注釈です。プログラムの実行には影響しません。プログラムの意味を説明したいときなどに利用します。
なお,このプログラムがどのように動いているのか見たいときは,210行のMAT PRINT文を適当な位置に移してみるとよいでしょう。

3.3.8 挿入ソート

再帰的な発想法を用いると,少し異なった種類の整列アルゴリズムを作ることができます。a(1)〜a(i-1)がすでに大きさの順に並んでいるとしたら,a(i)をしかるべき位置に挿入して以後の数値を順に後ろにずらしてやればa(1)〜a(i)が大きさの順に並びます。そこで,i=2からi=10まで順に上に述べた処理を繰り返せば大きさの順に並ぶことになります。

例44

100 DIM a(10)
110 MAT INPUT a
120 FOR i=2 TO 10
130    LET b=a(i)                  ! a(i)をbに退避する
140    LET j=i                     ! bを挿入すべき位置をjに求める
150    DO WHILE j>1 AND a(j-1)>b
160       LET a(j)=a(j-1)          ! データを後方にずらす処理も同時に行う
170       LET j=j-1
180    LOOP
190    LET a(j)=b
200 NEXT i
210 MAT PRINT a;
220 END

130〜180行でa(i)の値を挿入すべき位置を探しています。そのとき,同時に各変数の値を後ろにずらしています。
JIS Full BASICのANDとORには特徴的な性質があります。p AND qでは,pが偽であるとわかったときにはqの真偽を調べません。また,p OR qでは,pが真であるとわかったときにはqの真偽を調べません。150行のAND演算では,j>1とa(j-1)>bを調べる順序が重要です。150行ではj=1になることがありますから,j>1よりも先にa(j-1)>bを調べると添字が範囲外となってエラーになってしまいます。

3.4 例外状態処理

3.4.1 実行時エラー(例外)

PRINTをPLINTと綴ったり,FORに対応するNEXTがなかったりするとコンパイラはエラーを報告します。これは文法上の誤りです。
xの値が0であるときに1/x を計算すれば当然エラーになります。また,BASICには扱いうる最大の数が定められていて,計算結果の絶対値がその値(MAXNUM)を超える場合にもエラーになります(桁あふれ)。このように実行時に起こるエラーを特に例外と呼んで,文法上の誤りと区別します。
ゼロ除算のエラーならばあらかじめ除数が0であるかどうか調べておけば防げますが,桁あふれのエラーを予測するのは実質的に不可能です。このような場合にはエラーが起きてから対処するしか方法がありません。

3.4.2 WHEN EXCEPTION 構文

WHEN EXCEPTION構文は,実行時エラー(例外)が発生したときの処理を記述する構文です。次の形に書きます。

WHEN EXCEPTION IN

  例外を起こす可能性のある処理

USE

  例外が起きたとき実行すべき処理

END WHEN


WHEN EXCEPTION IN行とUSE行の間に書かれた文で例外が起こると,その文の実行を中断してUSE行の次の行に制御を移します。一方,WHEN EXCEPTION IN行とUSE行の間に書かれた文が例外を発生することなく実行されたときは,USE行とEND WHEN行の間に書かれた文は実行されません。
この構文は関数のグラフを描く場合には不可欠なものといえます。

例46 関数y = tan x のグラフ

100 OPTION ANGLE DEGREES
110 DEF f(x)=TAN(x)
120 SET WINDOW -180,180,-4,4
130 DRAW AXES(90,1)
140 FOR x=-180 TO 180
150    WHEN EXCEPTION IN
160       PLOT LINES: x,f(x);
170    USE
180       PLOT LINES
190    END WHEN
200 NEXT x
210 END


なお,180行のPLOT LINESがないと,たとえば,2点(89,TAN(89)),(91,TAN(91))を結ぶ線分が描かれてしまいます。




次に進む

戻る