roy > naoya > 基礎プログラミングI·情報検索 > (5)値の型変換
(5) 05/18の授業内容:値の型変換
[1] 値の型について(導入)
これまでgetsメソッドを使ってコンピュータに数字を入力したり、最初からプログラムの中にsum = 0というように初期値として数字を与えていた。特に問題なくこれで利用できていたが、問題点に気づいた人がいたかもしれない。これまでのプログラムでは実は小数を含む実数を取り扱うことができなかったのである。
これは前回のレポート課題で作成したプログラムに、レポートの得点として7.5点など小数を含む数値を代入してみれば容易に確認できる。
#!/usr/koeki/bin/ruby
a = 5
b = 2
c = a / b
p c
pメソッドは久しぶりの登場だが、変数内の値を表示するメソッドである。このプログラムを実行すると、2.5という結果が表示されるような気がする。しかし、実行結果はそうはならない。
pan{c10xxxx}% ruby value.rb[Return] 2
結果は2となっている。なぜだろうか?
我々は「123」は整数、「10.5」は実数(整数+小数)、「プログラミング」は文字列であると直感的に理解できる。しかしコンピュータは理解することができない。このため取り扱っている値が整数なのか実数なのか文字列なのかを明確に指示する必要がある。
値の型について
- コンピュータは値の型を理解することができない。「10」は整数、「1.5」は実数、「Ruby」は文字列であることを示してあげる必要がある。
[2] 初期値を与える場合の型の指定
a=10とプログラム中に記載した場合、aに10を代入するという意味になる。ではb=10.0と入力した場合はどうなるだろうか。c=3とし、d=a/c、e=b/cとした場合に何が異なるだろうか。まずは予想をしてから以下のプログラム(value.rb)を実行してみよう。
#!/usr/koeki/bin/ruby
a = 10
b = 10.0
c = 3
d = a / c
e = b / c
p d
p e
これを実行すると以下のようになる。
pan{c10xxxx}% ruby value.rb[Return] 3 #->p dの出力結果 3.333333333 #->p eの出力結果
a = 10とした場合、aに代入されている値は整数であると判断される。このため3で割っても小数点以下が切り捨てとなり、答えは3になっている。一方、b = 10.0とするとbに代入されている値は小数点以下を含む実数であると判断される。これにより3で割った答えにも小数点以下の値が含まれる。
初期値を与える際の型指定の方法
- a = 10の場合整数として扱われる。整数同士の割り算の結果小数点以下がでても表示されない。
- a = 10.0の場合実数として扱われる。割り算の結果小数点以下がでれば表示される。
[3] 出席課題
整数と実数を初期値として与える際の注意を見てきたが、今度は文字列を初期値として与える方法について復習しよう。具体的には以下のruby05.rbを実行してみる。余裕のある人は実行結果を確認した後でb = "200"をb = 200に変更して再度実行してみる。
#!/usr/koeki/bin/ruby
a = "100"
b = "200"
c = "Ru"
d = "by"
e = a + b
f = c + d
p e
p f
制限時間は10分。出席点は2点。提出要領は下記の通り。
- 提出先:課題提出先メールアドレス
- メールのSubject:ruby05
- 本文の構成:1行目で学籍番号、氏名を記載する。2行目以降に結果を貼り付ける。わかったことをその下に記載する。
[4] getsメソッドについて
キーボードからの入力を読み込むメソッドとしてgetsメソッドを使用してきた。これまではgets.chomp!.to_iというように後ろにchomp!.to_iをつけて利用してきたが、実はchomp!もto_iも特定の働きを持つメソッドである。
getsではなくgets.chomp!.to_iとしてきたのは、今回の授業で取り上げた値の型が関連する。getsメソッド、chomp!メソッド、to_iメソッドの働きについてここで確認してみよう。
- getsメソッド:キーボードからの入力を文字列として取得する
- chomp!メソッド:改行文字(\n)を取り除く
- to_iメソッド:値の型を整数に変換する
getsメソッドはキーボードからの入力を文字列として取得する。このため、ユーザーが数字の100(ひゃく)のつもりで入力しても文字列の100(いちぜろぜろ)として扱われてしまう。
さらに言えば、キーボードから入力する場合、入力後に確定のために[Return]キーを押す。[Return]キーは改行をあらわす\nとしてコンピュータ内では取り扱われる。このため、数字の100(ひゃく)を入力したつもりでも、コンピュータが受け取るデータは100\n(いちぜろぜろバックスラッシュエヌ)となっている。
そこで、getsメソッドにchomp!メソッドをつけることで、まずバックスラッシュエヌを取り除いている。その後、to_iメソッドをつけることで、文字列を整数に変換している。
getsメソッドについて
getsメソッドはキーボードからの入力を文字列として取得する。入力した値を整数として扱う場合はchomp!.to_iをつける。キーボードから100[Return]を入力した場合に変数に代入される値を確認しよう。
- a = getsの場合:aには100\n(いちぜろぜろバックスラッシュエヌ)が代入される
- a = gets.chomp!の場合:aには100(いちぜろぜろ)が代入される
- a = gets.chomp!.to_iの場合:aには100(ひゃく)が代入される
[5] 値の型変換(1):変換メソッド(to_i、to_f、to_s)
3つの値の型変換メソッドについて
to_iは値の型を整数に変換するメソッドであったが、実数に変換するメソッドや文字列に変換するメソッドもある。
値の型変換メソッド
- to_i:値の型を整数に変換する。小数点以下を含む値の場合は小数部は切り捨てになる
- to_f:値の型を実数に変換する。小数点以下を含む数字を取り扱うことができるようになる
- to_s:値の型を文字列に変換する。30は「さんじゅう」ではなく「さんぜろ」になるので数字の足し算や引き算はできなくなる
a = 10.0のようにプログラム内に具体的に値を記述できる場合は、プログラム作成時に配慮すれば、以後値の型を気にしなくても良いが、キーボードからの入力を受け取る場合はこれらのメソッドを使って値の型を指定しなければ全て文字列扱いとなってしまう。
これらの働きをプログラムの実行を通して確認してみよう(form.rb)。
#!/usr/koeki/bin/ruby
print"1つ目の数字を入力してください:\n"
a = gets.chomp! #=>to_iがついていないことに注意
print"2つ目の数字の入力してください:\n"
b = gets.chomp! #=>to_iがついていないことに注意
c = a + b
p c
d = a.to_i + b.to_i
p d
e = a.to_f + b.to_f
p e
f = a.to_s + b.to_s
p f
これを実行すると以下のようになる。
pan{c10xxxx}% ruby form.rb[Return] 1つ目の数字を入力してください: 100[Return] 2つ目の数字の入力してください: 45[Return] "10045" 145 145.0 "10045"
変換メソッドをつけずにa+bとした場合、getsは文字列として値を取り込むため、「100(いちぜろぜろ)」と「45(よんご)」の2つの値が入力されたことになり、これらの足し算をすると文字列が結合される。to_iやto_fをつけると数字として扱われることがわかる。
これらの型変換メソッドは、gets.chomp!.to_iのようにgets.chomp!に続けて使う以外に、このプログラムのように変数.to_iのように使用することもできる。
これらのメソッドをどこで使うか
to_iやto_f、to_sの各メソッドを使用する場所について注意しよう。なんでもかんでもgets.chomp!.to_iとするとうまくプログラムが動かない場合がある。次のプログラムregi.rbで確認しよう。
#!/usr/koeki/bin/ruby
sum = 0
while true
print"金額を入力(終了はquit):\n"
price = gets.chomp!.to_i
if price == "quit" then
break
end
sum += price
end
printf("合計%d円です。\n", sum)
このプログラムはwhile trueを使用しており、while-end内にif文でbreakをつけることで繰り返しから抜けるように書かれている。if文ではpriceに代入された値がquitの場合にbreakせよと書いており、ユーザーが金額を入力する代わりにquitと入力すれば繰り返しから抜ける。では、実行結果を見てみよう。
pan{c10xxxx}% ruby regi.rb[Return] 金額を入力(終了はquit): 198[Return] 金額を入力(終了はquit): 298[Return] 金額を入力(終了はquit): quit[Return] 金額を入力(終了はquit):
quitを入力しても終了しないことがわかる。このプログラムは永久に終了しない。なお、プログラムを実行したがどうしても止まらないという状況になった場合はCtrl+cで強制終了させることができる。
終了しない原因はprice = gets.chomp!.to_iにある。to_iがあるので、入力した値を整数に変換してからpriceに代入する。このためquitも整数に変換してpriceに代入している。quitなどの文字列は整数に変換すると0になる。このため、キーボードからquitを入力してもpriceに代入される際には0になってしまう。したがってこのプログラムではpriceに代入された値がquitであるというif文に記載された条件を満たすことができない。
正しく終了するためにはto_iの位置を変更する必要がある。gets.chomp!.to_iをgets.chomp!に修正し、to_iをsum += price.to_iの位置につけ、sumに金額を加算する際に整数に変換すればうまく動くようになる。
#!/usr/koeki/bin/ruby
sum = 0
while true
print"金額を入力(終了はquit):\n"
price = gets.chomp!
if price == "quit"
break
end
sum += price.to_i
end
printf("合計%d円です。\n", sum)
pan{c10xxxx}% ruby regi.rb[Return] 金額を入力(終了はquit): 198[Return] 金額を入力(終了はquit): 298[Return] 金額を入力(終了はquit): quit[Return] 合計496円です。
値の型変換メソッドをつける位置について
- 変数.to_iのように変数につけることができる。
- アルファベットや日本語を整数に変換すると0になる。
- プログラムが止まらなくなったらCtrl+cで強制終了できる。
[6] 値の型変換(2):printfを用いたフォーマット出力
printとprintfはこれまで何度か利用してきたが、使い分けはできるようになっただろうか。printは""内に入力されたメッセージをそのまま出力するメソッドである。一方、printfは変数内に代入されている値を出力する場合に""内に%dをいれ""の後ろに具体的に変数を指定することで、表示をおこなうメソッドであった。
printfの書式制御文字について
ここで%dとは果たして何を意味しているのであろうか。実は%dは%とdに分割することができる。厳密に言うと、%の位置に、""の後ろで指定された変数内の値を入れ込んで表示する。dは表示するときの形式(書式制御文字と呼ぶ)である。dはdecimal(10進数)の頭文字で、%dとした場合は変数内の値を「10進整数」で表示せよという意味になる。
我々が日常的に使用している数字は10進数と呼ばれるもので、0〜9の10種類の値を使用する。一方で、コンピュータの世界では0と1のみ使用する2進数、0、1、〜、9、a、b、c、d、e、fの16種類の数字を使用する16進数が利用されている。
printfで結果を出力する場合には、変数内の値を10進整数で表示する以外に、2進数や16進数、小数点を含む実数で表示することもできる。これにより、計算過程では.to_fをつけて計算を行ってきたが、結果を表示するときは小数点以下を切り捨てて整数で表示するというようなことも可能になる。主な書式制御文字は以下の通り。
printfの書式制御文字について
- d:10進整数の文字列に置き換える
- b:2進整数の文字列に置き換える
- x:16進整数の文字列に置き換える
- f:浮動小数点数の文字列に置き換える
- s:文字列に置き換える
format.rb
a = 100
printf("10進整数だと%d\n", a)
printf("2進整数だと%b\n", a)
printf("16進整数だと%x\n", a)
printf("浮動小数点数だと%f\n", a)
printf("文字列だと%s\n", a)
pan{c10xxxx}% ruby format.rb[Return] 10進整数だと100 2進整数だと1100100 16進整数だと64 浮動小数点数だと100.000000 文字列だと100
%fを指定した場合、デフォルトで小数点以下第6位まで出力される。
printfによる桁揃え出力
- %と書式制御文字の間に出力幅を指定する整数を書くことができる
- %4dのように「4」と入れると、結果を4桁で表示する
- 25(2桁)の場合には左側にスペースが2つ空く
- 137(3桁)の場合には左側にそれぞれスペースが1つ空く
- 整数の左にマイナスをつけて%-4dなどとすると左づめになる
- fの場合は6.2のように小数で指定する。
- これは全体の桁数が6桁で、小数点以下が2桁という指定になる。
- %fを桁の指定をせずに使用すると標準の6桁で表示される。
整数を入れると右づめになる printf ("答えは%6dです\n", a) #=>___100 整数にマイナスをつけると左づめになる printf ("答えは%-6dです\n", a) #=>100___ %fでは全体の桁、小数部の桁の順に指定する ここでは小数を含めて全体が6桁、小数は3桁になっている printf ("答えは%6.3fです\n", a) #=>_12.500
format.rbを実行した際に得られる結果表示を整えることを意識して書き直したプログラム(format2.rb)を示す。
a = 100
printf("10進整数だと%10d\n", a)
printf("2進整数だと%11b\n", a)
printf("16進整数だと%10x\n", a)
printf("浮動小数点数だと%6.1f\n", a)
printf("文字列だと%12s\n", a)
これを実行すると、綺麗に整えられた出力が得られる。format.rbの実行結果と比べ、見やすくなっていることがわかる。
pan{c10xxxx}% ruby format2.rb[Return] 10進整数だと 100 2進整数だと 1100100 16進整数だと 64 浮動小数点数だと 100.0 文字列だと 100
printfによる桁揃え出力
- %と書式制御文字の間に数字を入れることで桁揃えができる。
- %5dとすれば右づめで5桁表示される。
- %-4dとすれば左づめで4桁表示される。
- %fの場合のみ%5.2fのように実数で指定する。5は全体の桁数、2は小数点以下の桁数をあらわす。
[7] レポート課題
前回作成したreport2.rbについて以下3つの改良を施しなさい(report3.rb)(8点満点)。
- report2.rbではレポートの得点として、6.5点というような小数点を含む値を入力しても取り扱うことが出来なかったが、取り扱えるようにしなさい。
- report2.rbでは最後に合計得点と成績評価を表示したが、これに加えてレポートの平均点を表示できるようにしなさい(小数点以下は第1位まで)。出席点を含めた合計点でなく、レポートの合計点を用いて計算を行うこと。
- 入力したレポートの得点がマイナスの値の場合や、8点を超える場合には入力間違いとみなし、再入力をうながすことができるようにしなさい。
プログラムの変更点はこの3つであるが、難しい場合は出来るところまでで構わない。 一方で、余力がある人は以下の変更も行ってみよう。完成度に応じて加点します。
- 上の2番の変更を厳密にする。レポートは未提出の可能性があるので、未提出の場合を除いて平均点を算出できるようにする。例えば8回中6回提出(2回未提出)の場合、レポートの合計を6で割って平均点を算出する。提出回数を改めてキーボードから入力させるのではなく、while-endでレポートの得点を入力する際に「未提出」などと入力させ、この場合には提出回数にカウントしないなどの工夫をすること。
- 上の3番の変更を厳密にする。入力したレポートの得点が8点を超えている場合に、最初から入力間違いとみなすのではなく、正しい得点かどうか確認し(事実、驚異的によく出来ている場合には満点の8点を超える場合がある)、正しければ合計に加算、誤っていれば再入力ができるようにしてみよう。
提出要領
- 提出先:課題提出先メールアドレス
- 提出期限:5/24(日)23:00
- メールのSubject:report03
- 本文の構成:1行目で学籍番号、氏名を記載する。2行目以降は下記の構成とする
- 作成したプログラム
- プログラムの実行結果
- プログラムの説明
- 感想
作成要領
- 採点基準:期限内提出点(2点)、メールの体裁(1点)、プログラムの修正(3点)、プログラムの説明(2点)
- プログラムの説明は、report2.rbからの変更点について、今回学んだ値の型変換メソッドやprintfの書式制御文字に触れながら説明すること。触れていない場合は理解しているのかどうか判断できないため、減点する場合がある。3個目の修正も実施した場合はこれも説明すること。
- プログラムの修正については、3個の修正につき1つ1点で評価する。
- わかりにくい説明や、Webページを単にコピー&ペーストしただけの説明は減点することがある。一度読み直してから提出すること。
- 驚異的に良くできているレポートについては満点の8点を超える得点をつけることがある。
- よくできていたレポートは、他の人の参考になるよう、本人が特定できないような形で掲載する。掲載してほしくない場合はメールでの課題提出時にその旨記載すること。