フロー制御
条件付き制御 — if、else、switch
条件付きステートメントでは、ランタイムに実行するコードのブロックを選択できます。最もシンプルな条件付きステートメントは、if
ステートメントです。以下に例を示します。
% Generate a random number a = randi(100, 1); % If it is even, divide by 2 if rem(a, 2) == 0 disp('a is even') b = a/2; end
if
では、オプションのキーワード elseif
または else
を使用して、代替の選択肢を含めることができます。以下に例を示します。
a = randi(100, 1); if a < 30 disp('small') elseif a < 80 disp('medium') else disp('large') end
または、一連の既知の値を使用して等価性をテストする場合は、switch
ステートメントを使用します。以下に例を示します。
[dayNum, dayString] = weekday(date, 'long', 'en_US'); switch dayString case 'Monday' disp('Start of the work week') case 'Tuesday' disp('Day 2') case 'Wednesday' disp('Day 3') case 'Thursday' disp('Day 4') case 'Friday' disp('Last day of the work week') otherwise disp('Weekend!') end
if
と switch
のいずれの場合も、真である最初の条件まで対応するコードが実行されて、コード ブロックが終了されます。各条件付きステートメントでは、end
キーワードが必要です。
一般的に、考えられる既知の離散値が多数ある場合は、if
ステートメントよりも switch
ステートメントの方が読みやすくなります。ただし、switch
の値と case
の値の間で非等価性をテストすることはできません。たとえば、switch
で次のような条件を使用することはできません。
yourNumber = input('Enter a number: '); if yourNumber < 0 disp('Negative') elseif yourNumber > 0 disp('Positive') else disp('Zero') end
条件付きステートメントにおける配列の比較
関係演算子と if
ステートメントが行列にどのように機能するかを理解することは重要です。2 つの変数間の等価性をチェックする場合、次のようにします。
if A == B, ...
これは正しい MATLAB® のコードで、A
と B
がスカラーであるときに予想されることを実行します。しかし、A
と B
が行列の場合、A == B
はそれらが "等しいかどうか" をテストせずに、それらの "どこが等しいか" をテストします。結果は、要素ごとの等価性を表わす 0 と 1 からなる行列になります。
A = magic(4); B = A; B(1,1) = 0; A == B ans = 4×4 logical array 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
2 つの変数間の等価性をチェックする適切な方法は、関数 isequal
を使うことです。
if isequal(A, B), ...
isequal
は、関数 if
による結果の表現として、行列ではなく "スカラー" logical 値 1
(true
を表す) または 0
(false
) を出力します。上記の行列 A
と B
を使って以下を得ます。
isequal(A,B) ans = logical 0
次に、このことを強調する他の例を示します。A
と B
がスカラーである場合、次のプログラムは予想通りの結果になります。列を交換した魔方陣を含む行列のほとんどの組に対して、行列の条件 A > B
、A < B
、または A == B
は "どの" 要素に対しても真ではないため、else
句が実行されます。
if A > B 'greater' elseif A < B 'less' elseif A == B 'equal' else error('Unexpected situation') end
次の関数は、if
と共に使って、行列の比較結果をスカラー条件にするのに使うことができます。
isequal isempty all any
ループ制御 — for、while、continue、break
この節では、プログラムのループ制御を与える以下の MATLAB 関数を述べます。
for
for
ループは、前もって定義した固定回数だけステートメント群を繰り返し実行します。対応する end
でステートメント群を区別します。
for n = 3:32 r(n) = rank(magic(n)); end r
ループ内のステートメントの最後のセミコロンは、繰り返し表示されないようにして、最終結果を表示するためループの後に r
を使います。
読みやすくするため、特に入れ子状態のときには、ループにインデントを適用することは良い考えです。
for i = 1:m for j = 1:n H(i,j) = 1/(i+j); end end
while
while
ループは、回数を定義しないで、繰り返し回数を論理条件によりコントロールするときに使います。対応する end
でステートメント群を区別します。
while
、if
、else
、end
を使ったプログラムを示します。これは、多項式のゼロを見つけるために区間 2 分割を使います。
a = 0; fa = -Inf; b = 3; fb = Inf; while b-a > eps*b x = (a+b)/2; fx = x^3-2*x-5; if sign(fx) == sign(fa) a = x; fa = fx; else b = x; fb = fx; end end x
結果は、多項式 x 3 – 2 x – 5 の根になります。つまり、次のようになります。
x = 2.09455148154233
if
ステートメントの節で議論した行列比較に関する注意は、while
ステートメントにも適用されます。
continue
ステートメント continue
は、ループの本体の中で、for
、または、while
のループの中で、あるステートメントをスキップして、次の反復をコントロールします。入れ子のループ内の continue
ステートメントに対して同じことが当てはまります。つまり、continue
ステートメントが遭遇したループの初めで実行が続きます。
次の例は、continue
ループを使って、ファイル magic.m
の中の空白行とコメント行をスキップしたコードのラインをカウントするものです。continue
ステートメントを使って、空白行やコメント行に出会うとカウントしないで、magic.m
の中の次のラインに進みます。
fid = fopen('magic.m','r'); count = 0; while ~feof(fid) line = fgetl(fid); if isempty(line) || strncmp(line,'%',1) || ~ischar(line) continue end count = count + 1; end fprintf('%d lines\n',count); fclose(fid);
break
break
ステートメントは、for
または while
ループから抜け出すためのものです。入れ子になったループでは、break
は最下部のループのみから退出します。
前の節の例を改良したものを以下に示します。break
の使用はなぜ良い考えなのでしょうか?
a = 0; fa = -Inf; b = 3; fb = Inf; while b-a > eps*b x = (a+b)/2; fx = x^3-2*x-5; if fx == 0 break elseif sign(fx) == sign(fa) a = x; fa = fx; else b = x; fb = fx; end end x
プログラムの終了 — return
この節では、プログラムを最後まで実行せず途中で終了させる MATLAB 関数 return
について述べます。
出力
return
はコマンドの現在のシーケンスを終了し、起動関数またはキーボードに制御を戻します。return
は、keyboard
モードの終了にも使用されます。呼ばれた関数は通常その機能を終了すると、それを起動した関数に制御を移します。呼ばれた関数の中に return
を挿入することで強制的に早く終了し起動した関数に制御を移すことができます。
ベクトル化
MATLAB をスピードアップする 1 つの方法は、M ファイルのアルゴリズムをベクトル化することです。他のプログラミング言語が for
または DO
ループを使う部分で、MATLAB ではベクトルまたは行列演算を使うことができます。次のコードは、簡単な例として、対数表を作成するものです。
x = 0.01; y = log10(x); for k = 1:999 x(k+1) = x(k) + 0.01; y(k+1) = log10(x(k+1)); end
同じコードをベクトル化すると、次のようになります。
x = .01:.01:10; y = log10(x);
さらに複雑なコードに対しては、ベクトル化の効果が常に顕著とは限りません。
事前割り当て
コードの一部をベクトル化することができない場合、出力結果をストアする ベクトルまたは配列を前もって設定しておくことによって for
ループをスピードアップできます。たとえば、次のコードは、for
ループで作成されるベクトルを前もって作成するために関数 zeros
を使うものです。これにより、for
ループの実行はかなり速くなります。
r = zeros(32,1); for n = 1:32 r(n) = rank(magic(n)); end
前の例の中で前もってスペースを設定しないと、MATLAB インタープリターは、ループに関する 1 回の実行で、1 要素ずつ r
ベクトルを拡大します。ベクトルの領域を前もって確保することは、この手順を省略させ、より高速の実行になります。