roy > naoya > 基礎プログラミングI·情報検索 > (5)値の型変換

(5) 05/21の授業内容:値の型変換

値の型について(導入)

これまでgetsメソッドを使ってコンピュータに数字を入力したり、最初からプログラムの中にsum = 0というように初期値として数字を与えていた。特に問題なくこれで利用できていたが、問題点に気づいた人がいたかもしれない。これまでのプログラムでは実は小数を含む実数を取り扱うことができなかったのである。

これは前回のレポート課題で作成したプログラムに、アルバイト時間として5.5や4.2など小数を含む数値を代入してみれば容易に確認できる。

#!/usr/koeki/bin/ruby

a = 5
b = 2
c = a / b
p c

pメソッドは久しぶりの登場だが、変数内の値を表示するメソッドである。このプログラムを実行すると、2.5という結果が表示されるような気がする。しかし、実行結果はそうはならない。

irsv{naoya}% ruby value.rb[Return]
2

結果は2となっている。なぜだろうか?

我々は「123」は整数、「10.5」は実数(整数+小数)、「プログラミング」は文字列であると直感的に理解できる。しかしコンピュータは理解することができない。このため取り扱っている値が整数なのか実数なのか文字列なのかを明確に指示する必要がある。

値の型について

  • コンピュータは値の型を理解することができない。「10」は整数、「1.5」は実数、「Ruby」は文字列であることを示してあげる必要がある。

初期値を与える場合の型の指定

a=10とプログラム中に記載した場合、aに10を代入するという意味になる。ではb=10.0と入力した場合はどうなるだろうか。c=3とし、d=a/ce=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

これを実行すると以下のようになる。

irsv{naoya}% 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の場合実数として扱われる。割り算の結果小数点以下がでれば表示される。

出席課題

整数と実数を初期値として与える際の注意を見てきたが、今度は文字列を初期値として与える方法について復習しよう。具体的には以下のvalue2.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点。提出要領は下記の通り。

  • 提出先:naoya@e.koeki-u.ac.jp
  • メールのSubject:ruby05
  • 本文の構成:1行目で学籍番号、氏名を記載する。2行目以降に結果を貼り付ける。わかったことをその下に記載する。

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

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

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(ひゃく)が代入される

値の型変換(1):変換メソッド

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

これを実行すると以下のようになる。

irsv{naoya}% 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と入力すれば繰り返しから抜ける。では、実行結果を見てみよう。

irsv{naoya}% 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に代入している。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" then
    break
  end
  sum += price.to_i
end

printf ("合計%d円です。\n", sum)
irsv{naoya}% ruby regi.rb[Return]
金額を入力(終了はquit):
198[Return]
金額を入力(終了はquit):
298[Return]
金額を入力(終了はquit):
quit[Return]
合計496円です。

値の型変換メソッドをつける位置について

  • 変数.to_iのように変数につけることができる。
  • アルファベットや日本語を整数に変換すると0になる。
  • プログラムが止まらなくなったらCtrl-cで強制終了できる。

値の型変換(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)
irsv{naoya}% ruby format.rb[Return]
10進整数だと100
2進整数だと1100100
16進整数だと64
浮動小数点数だと100.000000
文字列だと100

%fを指定した場合、デフォルトで小数点以下第6位まで出力される。

printfによる桁揃え出力

%と書式制御文字の間に出力幅を指定する整数を書くことができる。%4dのように「4」と入れると、結果を4桁で表示せよということになる。25(2桁)や137(3桁)の場合には、左側にそれぞれスペースが2つ、1つ空くことになる。整数の左にマイナスをつけると左づめになる。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

printfによる桁揃え出力

  • %と書式制御文字の間に数字を入れることで桁揃えができる。
  • %5dとすれば右づめで5桁表示される。
  • %-4dとすれば左づめで4桁表示される。
  • %fの場合のみ%5.2fのように実数で指定する。5は全体の桁数、2は小数点以下の桁数をあらわす。

レポート課題

前回作成したkadai2.rbについて以下の改良を施しなさい(kadai3.rb)。

  1. 毎日のアルバイト時間として6.5など小数を含む値を入力しても正しく結果が出力できるようにする。
  2. 最後の結果出力場面において、アルバイトの合計時間とアルバイト代だけでなく、1日あたりの平均のアルバイト時間を表示できるようにする。

プログラムの変更点はこの2つであるが、難しい場合は一方でも構わない。余裕がある人は、これらに加えて平均のアルバイト時間に応じて適宜メッセージを出す(if文)など、いろいろなことに挑戦しても良い。

1番に比べて2番は難しい。平均時間は合計÷日数で求められるが、日数(数字を入力した回数)をどうやって求めるのかがポイントとなる。前回の授業のサンプルプログラムをよく眺めてみよう。

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

  • 採点基準:期限内提出点(2点)、メールの体裁(1点)、プログラムの修正(2点)、プログラムの説明(2点)、趣向を凝らしているか(1点)
  • プログラムの説明は、kadai2.rbからの変更点について、今回学んだ値の型変換メソッドやprintfの書式制御文字に触れながら説明すること。触れていない場合は理解しているのかどうか判断できないため、減点する場合があります。
  • わかりにくい説明や、Webページを単にコピー&ペーストしただけの説明は減点することがある。一度読み直してから提出すること。
  • 驚異的に良くできているレポートについては満点の8点を超える得点をつけることがある。
  • よくできていたレポートは、他の人の参考になるよう、本人が特定できないような形で掲載する。掲載してほしくない場合はメールでの課題提出時にその旨記載すること。

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

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

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