プログラムは実行すると、通常上から順番に実施される。これを逐次処理と呼んだが、プログラムの流れを変えるものが制御構造であった。制御構造には前回行った「条件判断」と今回行う「繰り返し」があった。「繰り返し」は条件に応じてある処理を何度も繰り返し実施するというものであり、前期ではwhile-endを取り上げた。
while-endの基本構造は以下の通りである。
while 繰り返し条件 繰り返す処理 end
ここでwhileの横には x < 10 や y >= i などのように繰り返しを継続する条件が記載された。この条件を満たす間はwhileとendの間にある処理を繰り返し行うというものであった。具体的に例をあげながらもう一度確認しよう。
#!/usr/koeki/bin/ruby sum = 0 goal = 10 i = 1 while i <= goal sum += i i += 1 end printf ("sumは%dです\n",sum)
このプログラムでは、3つの変数を使用しており、それぞれsum=0、goal=10、i=1という初期値を与えている。その後、while-endがあるが、whileの横には「i <= goal」とある。これが繰り返しを継続する条件である。具体的に繰り返す内容は、while-end間に書かれている「sum += i」と「i += 1」の2行である。
繰り返しを継続する条件である「i <= goal」は「iがgoal以下」という意味になる。iは初期値が1であり、goalは初期値が10である。while-end間を見ると、「i += 1」があることから、iの値は変化する(より厳密にはwhile-endの繰り返しを実施するたびに1ずつ増加する)ことになる。それに対してgoalは初期値が与えられているのみで、その後値は変化しない。つまり、iが1から2、3、4、・・・と増加していき、最終的に10まで繰り返し処理を継続せよということになる。
具体的に繰り返し継続される処理は「sum += i」と「i += 1」であった。これは「sumに現在のiの値を加算せよ」および「iに1加算せよ」ということになる。
while-end部の繰り返しがどのように行われるのかを表にして示してみよう。
繰り返し回数 | while i <= goal | sum += i | i += 1 |
1回目 | iは1なので条件を満たす | sumは1に | iは2に |
2回目 | iは2なので条件を満たす | sumは3に | iは3に |
3回目 | iは3なので条件を満たす | sumは6に | iは4に |
4回目 | iは4なので条件を満たす | sumは10に | iは5に |
5回目 | iは5なので条件を満たす | sumは15に | iは6に |
6回目 | iは6なので条件を満たす | sumは21に | iは7に |
7回目 | iは7なので条件を満たす | sumは27に | iは8に |
8回目 | iは8なので条件を満たす | sumは35に | iは9に |
9回目 | iは9なので条件を満たす | sumは44に | iは10に |
10回目 | iは10なので条件を満たす | sumは55に | iは11に |
11回目 | iは11なので条件を満たさない(終了) | 実行されない | 実行されない |
繰り返しを行うごとにsumおよびiの値が増加していき、11回目の時点でiが11となり「while i <= goal」の繰り返し条件を満たさなくなるためこれで終了となる。
while-endを用いる場合、whileの横に繰り返し条件を具体的に記述する変わりに「while true」と記述することもあった。これは永久に繰り返しを継続するという意味であった。while trueを使用する場合は、while-end内に別途、繰り返しから抜けるための「break」を記述しておく必要があった。以下の前期のレジスターのプログラムであり、購入した商品の単価(price)を連続して入力することで、購入した商品数(item)と合計金額(sum)を算出するものである。そして、ユーザがキーボードから「q」を入力した場合に繰り返しから抜けよという指示がされている。
priceにはユーザがキーボードから入力した値が代入される。「price = gets.chomp!」の行がそれにあたり、この行はwhile-end内に記述されている。つまり繰り返しを継続するかどうかは、whileの行では判断できず、while-end内の処理を実行して初めて決定する。このようなケースではとりあえず繰り返しは続けておき、繰り返し処理を行う中で終了するかどうかを判断するという、while trueが利用される。
#!/usr/koeki/bin/ruby
sum = 0
item = 0
while true
print "金額を入力してください(終了はq): "
price = gets.chomp!
if price == "q"
then break
end
sum += price.to_i
item += 1
printf ("現時点の購入商品の個数は%d個、合計は %d 円です\n", item, sum)
end
printf ("ありがとうございます。お会計は %d 円になります\n", sum)
なおこのプログラムの黄色の部分が繰り返しから抜けるかどうかの判定部であるが、「if price == "q" 」となっている。左辺は"q"であるが、文字の場合は""をつける。もしも数字で9999と入力したら終了としたければ「if price == 9999」となる。ただしこのプログラムに関しては「if price == "9999"」と書かなければならない。「price = gets.chomp!」の行で入力した値を取得してpriceに代入しているが、getsメソッドは文字列として取得する。つまり9999と入力したとしても整数の「きゅうせんきゅうひゃくきゅうじゅうきゅう」ではなく文字列の「きゅうきゅうきゅうきゅう」として扱われていることになる。整数に変換するためには.to_iメソッドを使用する必要があり、「price = gets.chomp!.to_i」としなければならない。このプログラムでは「sum += price.to_i」の行でpriceに.to_iをつけ整数に変換している。「price = gets.chomp!.to_i」としていないのは、ユーザが金額(整数)と終了のq(文字)を入力する可能性があり、最初に全て整数に変換してしまうと都合が悪いからである。なお文字を.to_iメソッドで整数に変換すると0になってしまう。このため「price = gets.chomp!.to_i」とするとqと入力しても0に変換されてpriceに代入されてしまい、price内の値がqである場合に繰り返しから抜けるという条件を満たすことがなくなってしまう。
以下のプログラムは1から10までの足し算を行うプログラムである。これを1からユーザが指定した任意の自然数(=正の整数)までの足し算を行うことができるプログラムに改良せよ。
#!/usr/koeki/bin/ruby sum = 0 goal = 10 i = 1 while i <= goal sum += i i += 1 end printf ("sumは%dです\n",sum)
制限時間は10分。出席点は2点。提出要領は下記の通り。
Tips:emacsでの日本語入力のオンオフはCtrl-oです
Tips:Mewによるメールの送り方はMewコマンドを参照
情報検索の授業では、繰り返しを行う際、主にwhileを用いてきた。ただし繰り返し処理にはwhile以外にもいくつかの方法がある。様々な方法を理解して自在に扱えるようにしよう。
timesは単純に一定回数繰り返す場合に用いる。以下のどちらの方法で記述しても構わない(times.rb)。
#!/usr/koeki/bin/ruby 4.times { print "Hello\n" }
#!/usr/koeki/bin/ruby 4.times do print "Hello\n" end
irsv{学籍番号}%chmod +x times.rb ./times.rb Hello Hello Hello Hello
1から10までの合計を出すことを考えてみよう。while-endで記述した場合以下の通りとなる。
#!/usr/koeki/bin/ruby goukei = 0 i = 1 while i <= 10 goukei += i i += 1 end printf ("goukeiの値は%dです\n",goukei)
このプログラムではiの初期値を1とし、繰り返しを行うごとにiの値を1ずつ増加しながらgoukeiに加えている。そしてiが10を超えたら終了になるため、結果的に1から10までの合計を出したことになる。
○から□まで1ずつ変化させながら処理を繰り返し行うという場合、while以外にuptoメソッド、downtoメソッドを使って表現することもできる。以下はuptoメソッドを用いて上記のプログラムを書き直したものとなる(sum-upto.rb)。
#!/usr/koeki/bin/ruby
goukei = 0
1.upto(10) do |i| #from.upto(to)。1から10までiを1ずつ増加させる。
goukei += i
end
printf ("goukeiの値は%dです\n",goukei)
同様にdowntoメソッドを用いて書き直すと下記のようになる(sum-downto.rb)。
#!/usr/koeki/bin/ruby
goukei = 0
10.downto(1) do |i| #from.downto(to)。10から1までiを1ずつ減少させる。
goukei += i
end
printf ("goukeiの値は%dです\n",goukei)
uptoメソッド、downtoメソッドの基本構造はそれぞれ以下の通りである。初期値と終了値をそれぞれfromとtoの位置に指定する。繰り返し処理を行う中でuptoメソッドはfromからtoまで変数の値を1ずつ増やしながら、downtoメソッドでは1ずつ減らしながら処理を継続する
from.upto(to) do |変数| 繰り返す処理 end
from.downto(to) do |変数| 繰り返す処理 end
なお、3.upto(1)のようにuptoメソッドにおいて初期値よりも終了値に小さな値を指定した場合や、1.downto(10)のようにdowntoメソッドにおいて初期値よりも終了値に大きな値を指定した場合は1回も処理は行われない。
もうひとつ、連続した整数を繰り返すには、forと整数範囲を用いた表現も可能である。整数範囲には1..10のように初期値と終了値を指定する。そして初期値から終了値まで1ずつ変化させながら変数に代入し、繰り返し処理を行う。
for 変数 in 整数範囲 繰り返す処理 end
これで1から10までの合計を記述すると以下のようになる(sum-for.rb)。
#!/usr/koeki/bin/ruby
goukei = 0
for i in 1..10 #iに1から10まで順次代入する
goukei += i
end
printf ("goukeiの値は%dです\n",goukei)
uptoやdowntoは1ずつ増加、減少させながら繰り返し処理を行うためのメソッドである。では、10+20+30+、、、+100のように10ずつ増加する場合や、2+4+6+、、、+10のように2ずつ増加する場合はどうすればよいだろうか。これについてもまずはwhileでの表現方法を見てみよう。
#!/usr/koeki/bin/ruby goukei = 0 i = 10 while i <= 100 goukei += i i += 10 end printf ("goukeiの値は%dです\n",goukei)
このようにiの初期値を10として、繰り返しを行う中で10ずつ増加させていけば書くことができる。なお、一定間隔で値を変える方法として、stepメソッドもある。stepメソッドの基本構造は下記の通りとなる。
初期値.step(終了値, 増加値) do |変数| 繰り返す処理 end
stepメソッドでは3つの値を指定する。初期値と終了値はuptoメソッド、downtoメソッドと同様であるが、加えて増加値を指定する。これにより10ずつ増加させるということが可能になる。
増加値は省略可能であるが、この場合は増加値=1とみなされる。10から100まで100ずつ増加させて加算するプログラムを書くと以下のようになる(sum-step.rb)。
#!/usr/koeki/bin/ruby goukei = 0 10.step(100, 10) do |i| goukei += i end printf ("goukeiの値は%dです\n",goukei)
増加値には負の値を入れることもできる。10から初めて100まで10ずつ増加させながら足し算をするということは、100から初めて10まで10ずつ減らしながら足し算をすることと同義である。上記のプログラムの開始値、終了値、増加値をそれぞれ100、10、-10に変更しても同じ結果となる。
以下のうちいずれかを選んで解答する。プログラムはwhile-end以外の繰り返し表現を用いて記述すること。while-endを用いた場合や繰り返し表現を用いなかった場合は、配点を1点マイナスとする(例えば、9点満点の問題は8点満点で採点)。
問題1(7点満点):指定した任意の自然数(=正の整数)からはじめて、100までのその自然数の倍数を全て足した値を求めるaddsum.rbを作成せよ
問題2(9点満点):1から100までの素数の和を求めるprime.rbを作成せよ。ここで、素数とは1とその数以外に約数がない正の整数を指し、結果は例えば素数が1,2,3,5である場合「1+2+3+5=11」というように式形式で表示されるようにせよ
Tips:emacsでの日本語入力のオンオフはCtrl-oです
Tips:ktermでのプログラムの実行結果をメールに貼り付けるには、コピーしたい箇所をマウスで選択し、emacs(Mew)上でマウスの真ん中ボタンをクリックする
Tips:Mewによるメールの送り方はMewコマンドを参照