IGORプログラミング:データの一括処理に至る道⑤:ループ②(回数不明ループ)

回数が不明のループとは

今回は、前々回に続いて ループ処理 のお話です!🔥 前回は、「整数を1から100まで順番に足す」など、繰り返し回数があらかじめ分かっている 場合のループとして、for~endfor を使う方法を紹介しました。

「n回繰り返す」と最初から決まっているなら、for~endforがシンプルで最適! 変数で回数を指定する場合でも、「最初にnが決まっている」なら、やはりfor~endforを使うのが自然です。

では!次のような場合はどうでしょうか?
「数字を1から順番に足していき、和が初めて100を超えたら終了!」

この場合、何回足せば100を超えるのか、最初から確定していない ので、for~endforでは扱いにくくなります。もちろん、数学的に計算して回数を求めることもできますが…

ここでさらに、条件をレベルアップ!
例えば、「ユーザーが入力したnを超えたら終了」 という仕様にする場合、nが何であるかによって回数が変わります。さらに、「関数のフィッティングを繰り返し、前回と今回の誤差が一定以下になったら終了」 なんて場合はどうでしょう?

「何回繰り返したら終わるのか、事前にはわからない」 こういうケースでは、for~endforではなく、別のループが必要になります!

というわけで、今回のテーマは 「終了条件は明確だが、回数が決まっていないループ処理」 です!

do~while(条件式)

このような回数が事前にわからないループでは、「do~while」ループ が大活躍します!まずはサンプルプログラムをご覧ください。

function do_while_test()
	variable i=0   // iを繰り返しカウンタとして使うのであれば、きちんとゼロに初期化しておく
	
	do
		print i
		i+=1 // for~endforとは違い、自動的にiが更新されたりはしないので、繰り返し回数が必要なら自分で足していく必要がある
	while(i<10) // ()内の条件が満たされている場合、doに戻る

end

実行結果は次の通りです。

使い方はとってもシンプルです!まず、do 以下の処理が必ず 1回実行 されます。その後、while に到達した時点で、カッコ内の条件式をチェックします。もし条件が満たされていれば、再び do に戻ります。

今回のプログラムでは、最初に変数 i をゼロに初期化しています。初回の i はゼロですが、while 文の直前で i+=1 によって i の値が1増えます。したがって、while に達したとき、i は1となり、カッコ内の i<10 を満たしているので、再び do に戻ります。

次の繰り返しでも、同様に i+=1 によって i が増加し、i が2、3、4と増えていきます。このプロセスを繰り返し、i=9 のときに do に戻り、次に while に達するときには i が10になっています。この時点で i<10 の条件を満たさないため、ループを終了します。結果として、i が0から9まで、合計10回の繰り返しが行われます。

あれ?for~endforと同じでは?

と思われた方、いらっしゃいますよね?

実際、先ほどの例では、for~endfordo~while の結果は同じです。しかし、繰り返し回数が事前に分かっている場合 には、for~endfor を使う方がいいんです!その理由を理解するために、次に do~while でよくあるミスを見てみましょう。

よくあるミス:初期条件によらずdo以下が一回実行されてしまう!

for~endfordo~while の大きな違いの一つは、繰り返しの判定タイミング です。for~endfor では、ループの開始時に条件をチェックしますが、do~while では、ループ内の処理を一度実行した後に条件を確認します。

例えば、以下の for~endfor のコードでは、変数 i を10に初期化し、i < 10 という条件でループを設定しています。しかし、初めから条件を満たしていないため、ループ内の処理は一度も実行されません。

function for_endfor_test()
	variable i
	
	for(i=10;i<10;i+=1)
		print i
	endfor

end

【実行結果】

では、似たようなことをdo~whileでやるとどうなるでしょうか?

function do_while_test_2()
	variable i=30 // while文に書かれた条件を満たしていない 
	
	do
		print i
		i+=1 
	while(i<10) // ()内の条件が満たされている場合、doに戻る

end

この場合、実行結果はこうなります。

なんと、このコードを実行すると、i の初期値が30で i < 10 の条件を満たしていないにも関わらず、print i が一度実行され、30が出力されます。これは、do~while ループが条件判定を後から行うため、初期条件に関係なく、ループ内の処理が最低一回は実行されるからです。

このように、do~while ループでは、初期条件に関わらずループ内の処理が一度は実行される点に注意が必要です。そのため、繰り返し回数が明確に分かっている場合 には、for~endfor を使用する方が安全で分かりやすいです。

よくあるミス②:無限ループにご注意!

do~while ループを使う際、特に気をつけたいのが 無限ループ です!これは、ループを終了させるための条件が永遠に満たされない場合に発生します。例えば、カウンタ変数の更新を忘れてしまうと、ループが永遠に続いてしまいます。

以下のコードを見てみましょう。

function do_while_test3() //実行してはいけないコード
	variable i=0
	
	do
		print i
		// ここにあるはずの i+=1 を書き忘れている
	while(i<10) 

end

皆さんは実行しないほうがよいですが、もしこれを実行してしまうと次のような無限ループになります。(実行してしまった場合はIGOR画面の右下か左下にでるAbortボタンを押して関数を強制終了してください)

この例では、変数 i0 に初期化しています。しかし、ループ内で i を増やす処理を忘れているため、i は常に 0 のままです。その結果、i < 10 の条件が永遠に真となり、ループが終わりません。

無限ループに陥った場合、プログラムが応答しなくなることがあります。そのため、do~while ループを使用する際は、ループ内で条件を変化させる処理を確実に行い、意図したタイミングでループが終了するように注意しましょう!

回数不明ループの例

では、具体的な例として、「1から順に数字を足していき、その合計が初めて100を超えるまで繰り返す」 ループを作成してみましょう!このような状況では、繰り返し回数が事前に分からないため、do~while ループが最適です。

以下のプログラムでは、変数 i0 に初期化し、合計を保持する変数 sums0 に初期化します。ループ内で i1 ずつ増やし、その値を sums に加算していきます。sums100 を超えるまで、この処理を繰り返します。

function do_while_sum100()
	variable i=0
	variable sums=0// 和。「sum」という変数を使いたいがIGORにはsumという命令があるため少し変えて「sums」とした
	do
		i += 1 // iを1増やす
		sums += i // sumsにiを足す
	while(sums<100)
	printf "i=%dを足したところで合計が100を超えて%dになりました。\r",i,sums
end

最後の「printf」というところは次回説明するのでいったんおいておいてください。

このプログラムを実行すると、i14 のときに sums105 となり、初めて 100 を超えます。その結果、ループを抜けて、「i=14を足したところで合計が100を超えて105になりました。」 と表示されます。

このように、do~while ループを使用することで、終了条件は明確だが、繰り返し回数が事前に分からない 場合の処理を簡潔に記述できます!

何の役に立つの?

今回の例だとあまり実用的なループじゃないように見えますよね?
でも実際はかなり実用的なループなんです!

それは。。。

次回「printf」「sprintf」「waveexists」と組み合わせて紹介します。
お楽しみに!

Follow me!

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です