(3) 10/23の授業内容:繰り返しの復習と他の繰り返し表現

繰り返し表現の復習

whileの横に繰り返しを継続する条件を記載する場合

プログラムは実行すると、通常上から順番に実施される。これを逐次処理と呼んだが、プログラムの流れを変えるものが制御構造であった。制御構造には前回行った「条件判断」と今回行う「繰り返し」があった。「繰り返し」は条件に応じてある処理を何度も繰り返し実施するというものであり、前期では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 <= goalsum += ii += 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 true

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点。提出要領は下記の通り。

  • 提出先:naoya@e.koeki-u.ac.jp
  • メールのSubject:ruby03
  • 本文の構成:1行目で学籍番号、氏名を記載する。2行目以降に作成したプログラムと変更点の説明を記載すること。

Tips:emacsでの日本語入力のオンオフはCtrl-oです

Tips:Mewによるメールの送り方はMewコマンドを参照

その他の繰り返し表現について

情報検索の授業では、繰り返しを行う際、主にwhileを用いてきた。ただし繰り返し処理にはwhile以外にもいくつかの方法がある。様々な方法を理解して自在に扱えるようにしよう。

一定回数繰り返す(times)

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」というように式形式で表示されるようにせよ

  • 提出先:naoya@e.koeki-u.ac.jp
  • 提出期限:10/29(日)23:59
  • メールのSubject:自分の学籍番号-kadai01
  • 本文の構成:1行目で学籍番号、氏名を記載する。2行目以降は下記の構成とする
  1. 作成したプログラム
  2. プログラムの実行結果
  3. プログラムの説明
  4. 感想

  • 採点基準:期限内提出点(2点)、メールの体裁(1点)、プログラム(2点or4点)、プログラムの説明(2点)
  • プログラムの説明:使用した繰り返し表現部について説明すればよい(=1行1行説明しなくてもよい)。なお単にWebページに記載された定義を丸写しにするのではなく、自分が作ったプログラムでは具体的にどのような値を指定し、繰り返し処理として何を実施しているのかを述べること。その他にもプログラムを作成して気づいた点があれば述べよ。
  • 説明に関して、文章の意味がわかりづらい場合や、Webページを単にコピー&ペーストしたものは減点することがある。一度読み直してから提出すること。
  • 驚異的に良くできているレポートについては満点を超える得点をつけることがある。
  • よくできていたレポートは、他の人の参考になるよう、本人が特定できないような形で掲載する。掲載してほしくない場合はメールでの課題提出時にその旨記載すること。

Tips:emacsでの日本語入力のオンオフはCtrl-oです

Tips:ktermでのプログラムの実行結果をメールに貼り付けるには、コピーしたい箇所をマウスで選択し、emacs(Mew)上でマウスの真ん中ボタンをクリックする

Tips:Mewによるメールの送り方はMewコマンドを参照