gets.chomp
という
method を二つ組み合わせたものを使うと、ユーザの入力部分
文字列 + \n
を
gets
(GET String, 文字列を取ってくる)
し、改行文字
\n
を
chomp
(噛み取る) という
組み合わせた動作
を行った。
変数 = gets.chomp
文字列を数値にするには、
to_i | 整数値 |
to_f | 小数値 |
を使えばよい。
to_i
は
小数点以下を切り落とす
ことに注意せよ。
to_i method をうまく四捨五入に使いたい。 四捨五入ができると、 例えば消費税の計算などに応用できる。 変数の代入部分をどのように変更すると、 四捨五入して表すことができるか。
ヒント: 小数点以下にひと工夫せよ。
日常のいろいろなところに、分岐がある。Ruby では
if -- end
として表す。
比較演算子は、条件を判断するときに使われる。前回は同じであるか調べる
==
を学んだ。
if A == B もし A が B に等しければ
C を実行せよ
elsif A == D A は (B に等しくないが) D に等しければ
E を実行せよ
else F を実行せよ A は B にも D にも等しくないから
end
となる。 A が B にも D にも等しくない場合は F が実行される。 洗濯物を洗う場合を考えてみよう。
白ければ漂白剤を入れて洗うし、毛糸製品はよりわけてクリーニングに出すであろう。 色ものであれば柔軟剤を入れて洗う。
本筋ともっとも遠いものを選り分けると組み立てやすい。 上の例ではどの事例がもっとも遠いだろうか。根拠をつけて答えよ。
これをプログラム風に分解してみよう。
if 洋服 == 毛糸製品クリーニングに出すelsif 洋服 == 白いもの漂白剤を入れて洗うelse 柔軟剤を入れて洗う end
while
文は反復処理を行う。
反復を止めさせるには、止める限界を
while
のすぐ後ろに書き込んでおく方法と、
ユーザが止めたいと思ったときに、止めるよう
while
文の中で分岐を作っておく方法とがあった。
while 限界についての記述
:
限界についての変数の変更
end
while true 言われない限り止まらない
if 終るときの条件
break
end
end
while
文や
if
文で条件を比較するとき、
「以上」や「以下」を含むこともあるだろう。以下にまとめておく。
比較演算子には、
A < B | A が B より小さい |
A <= B | A が B 以下 |
A >= B | A が B 以上 |
A > B | A が B より大きい |
A == B | A と B が等しい |
などがある。
3 歳以下は入場無料というと、何歳何カ月まで入場無料か。 20 歳未満は、不等号でどのように表されるか。
プログラムに必要なのは、目的である。 目的別にプログラムを組み立てる必要がある。 目的の解決のために順序立てて考えることをアルゴリズム Algorithm という。
目的までの個別に行動を分解し、 組み立て直すとプログラムの立て方が見えてくる。 公益ルビ緒のとった行動 「雨が降ったので、おりたたみ傘を使って帰った」 について考える。 ルビ緒の行動を、分解してみよう。
「帰りたくなった」 「外は雨が降っている」 「かばんの中におりたたみ傘があるかどうか判断する」 (なければ「走って帰る」「止むまで待つ」などの選択があるかもしれない) 「傘を開く」 (「もし傘を持っていない友だちを見つけたら入れてあげる」)
となる。 ルビ緒ロボットが真似をすると...
何を達成すると終了するのか、考える。
達成する事項を決定したら、
そのために必要な変数を設定する。
達成しなくても終了する場合は、この変数のとる値によって、
終了する動作を変更する。すなわち
if
文で分岐を作る。
変化を持たせるために、別の変数を設定し、物語を増やしていく。
RPG やお小遣い帳など、 ソフトウェアを作ることを念頭に、プログラミングの構想を作り、企画せよ。
ルビ緒ロボットが真似たらどのようになるだろうか。 このプログラムのソースの大まかな部分は
if 雨が降る傘をさすend
であるが、もう少し段階を踏むと、例えばまずは傘を持っているかどうか調べる。 その部分を増やしてみよう。
if 雨が降るif おりたたみ傘があるend家に帰るend
となる。
ルビ緒の行動をより細かく分析する。 傘を開く動作をルビ緒ロボットのプログラムに入れるとすると、 どのように書き著せばよいか考えてみよう。
ある程度行動が決まっているものを、整頓するとプログラムに使うことができる。
子ども番組の主人公と周囲のキャラクタの 30 分間における行動についてまとめ、 Ruby 言語のプログラム風に書き直してみよ。
あまりにも壮大すぎるアイディアしか思いつかない、 あるいはまったく思いつかないと言って、 プログラミングすることをあきらめる学生をときどき見かける。 まずはアイディアを小さく分類して、 自分の力でできるところを見つける と、作りやすい。
目標を設定し、
最終段階を作って
から、細かいところを詰めていくようにする。
ユーザーは設計者と全く考えが異なる。
変数のとりうる可能性を調べながら作る。
配布する段階では変数表示を取り去るが、
作成段階では必ず変数を
printf
文で表示させながらプログラミングする。
変数のとりうる可能性を調べながら作ることを
debug
という。
計算機は、人間が作成したプログラムをひたすら実行するだけの存在である。 計算機は計算があっているかどうか判断しない。 実際の計算と計算機が出した数値があっているかどうか調べるとき、電卓のほかに、 コマンドライン bc -l が使える。3,4,5,6 という 4 つの数値の平均値を調べたいとき、
%bc -lEnter (3 + 4 + 5 + 6) / 4Enter 4.50000000000000000000 quitEnter
とする。終了は quit と入力する。 bc -l を使うと、 結果を予想したり、どのように考えていくか、計画を立てながらプログラムを作成できる。 また、計算の結果を調べながら実行結果について考察することができる。
コマンドを使用した結果の数値は、プログラムとどのくらい異なるか。 小数点以下について着目し、 Ruby で同じ結果を求める部分と比較し、 何が違うか答えよ。 「有効数字」という言葉を使うと解答しやすいかもしれない。
プログラムに何か書いておきたいこともある。 そのようなメモをコメント文と呼ぶ。
実行文 # コメント文
と書く。# をつけると、 人間の目には見えるが、 計算機は # 以降を読まなくなる。
debug にもコメント文を使うことができる。 ある変数 questo があり、その振る舞いが分からないとき
:
printf("questo に入っている現在の値 questo = %d\n",questo)
STDERR.print("それでは次の問題です!\n")
:
などと挟んで、値を調べることができる。 エラーの出た直前の行から 1 行目に向かって間違いがないか調べていく。 しばらく使わないときには、 変数の値を調べた場所をコメントアウト # すればよい。
:
#printf("questo に入っている現在の値 questo = %d\n",questo)
:
# をつけ忘たり、括弧の閉じ忘れ、double quatation の閉じ忘れなどで、 実行時に次のようなメッセージが出ることがある。
%./mistake.rb [˜/Ruby]
./mistake.rb:7: Invalid char `\313' in expression
:
./mistake.rb:7: Invalid char `\271' in expression
./mistake.rb:7: syntax error, unexpected $undefined, expecting ')'
printf("僕の名前は%sです"\n
^
./mistake.rb:7: unterminated string meets end of file
./mistake.rb:7: syntax error, unexpected $end, expecting keyword_end
というエラーが出た場合、mistake.rb の 7 行目でエラーが出たということが分かるので、 その前 から順に戻りながらミスがないかをチェックしよう。
i -= 10
while i > 0
printf("こんにちは\n)
printf("僕の名前は%sです\n")
i -= 1
end
6 行目が間違っていることがわかる。
間違いに気づいてもらえるのは、言われた処理を実施しようとして、なので、 その前の行までにエラーが必ず存在する。9 行目なら 1 から 9 行目までを調べよう。
Kterm で日本語入力をしたいときは Kinput2 を使う。 Kterm で Ctrl-o で、 ON/OFF しながら使う。 日本語入力の練習として gets_parrot.rb で日本語を入出力しておこう。 使えないときには Shift Space も試してみよう。
実行し、日本語入力を立ち上げ、入力してみよう。 日本語が表示されただろうか?
桁の箱が 10 で繰り上がるものが、10 進数 (Decimal) である。人間が使っている進数である。 以降 0d を始めにつけて表すことがある。通常は何も定義されていなければ、 すべて 10 進数である。例えば 0d 89701456 という数は、次のように箱に入っている。
10 進数の箱 | 10**7 | 10**6 | 10**5 | 10**4 | 10**3 | 10**2 | 10**1 | 10**0 |
---|---|---|---|---|---|---|---|---|
0 から 9 | 8 | 9 | 7 | 0 | 1 | 4 | 5 | 6 |
Ruby 言語では、"乗" は、** で表す。
桁の箱が 2 で繰り上がるものが、2 進数 (Binary) である。 計算機が使う進数である。0b を前につけて区別する。 0b 10101010 = 0d 170 は 2 進数の箱に次のように入っている。
2 進数の箱 | 2**7 | 2**6 | 2**5 | 2**4 | 2**3 | 2**2 | 2**1 | 2**0 |
---|---|---|---|---|---|---|---|---|
10 進数表示 | 128 | 64 | 32 | 16 | 8 | 4 | 2 | 1 |
0 または 1 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 |
桁の箱が 16 で繰り上がるものが、16 進数である。 人間が機械の情報と照らしあわせるときに使う進数である。 10 進数 10 以降の数が定義されていなかったため、 0d10 = 0x0a, 0d11 = 0x0b, 0d12 = 0x0c, 0d13 = 0x0d, 0d14 = 0x0e, 0d15 = 0x0f, と名前をつけている。0x を前につけて表す。 0x 2136fa46 は次のように箱に入っている。
16 進数の箱 | 16**7 | 16**6 | 16**5 | 16**4 | 16**3 | 16**2 | 16**1 | 16**0 |
---|---|---|---|---|---|---|---|---|
10 進数表示 | 268435456 | 6291456 | 393216 | 24576 | 1536 | 256 | 16 | 1 |
0 から f | 2 | 1 | 3 | 0 | f | 4 | a | 6 |
2 進数、10進数、16進数についてまとめた。
16 進数表示 | 2 進数表示 | 10 進数表示 |
---|---|---|
0 | 0 | 0 |
1 | 1 | 1 |
2 | 10 | 2 |
3 | 11 | 3 |
4 | 100 | 4 |
5 | 101 | 5 |
6 | 110 | 6 |
7 | 111 | 7 |
8 | 1000 | 8 |
9 | 1001 | 9 |
a | 1010 | 10 |
b | 1011 | 11 |
c | 1100 | 12 |
d | 1101 | 13 |
e | 1110 | 14 |
f | 1111 | 15 |
2 進数で 0b 10111010100 ならば、16 進数では
2 進数の箱を右端から 4 桁ごとに区切る | 101 | 1101 | 0100 |
---|---|---|---|
4 桁ごとに 16 進数で書き直す | 5 | d | 4 |
となり、0b 10111010100 = 0x 5d4 であると分かる。
人間は 10 進数で数えるが、計算機ではメモリ内部では 2 進数で数を数える。 そこで人間は計算機の結果を 16 進数で数えたあと、10 進数に変換したり、 逆に人間が計算機に 16 進数で指示したりする。
メモリとは、箱を多数用意したもので、二種類の状態がある。 計算機では状態を 0 と 1 で区別する。 これを箱にカードを入れることで表現してみよう。 箱が 5 つあった場合、31 まで数えることができる(0 を含む)。
8 個の箱を一つの組とし、255 まで数えることができる(0 を含む)。
ハードウェアやメモリの問題などは 16 進数でエラーメッセージが出現することがある。
2 進数では 31 をたった 2 枚のカード 5 セットすなわち 10 枚で済むが、 10 進数は 10 枚のカード 3 セットすなわち 30 枚も必要になる。 メモリに必要なカードの枚数が少ないので、2 進数が使われる。
繰り上がりが 16 を越えなければ普通の 10 進数と同じように解ける。 練習問題として、16 進数のままで以下の問題を解いてみよう。
0x12 + 0x21 = 0x33 = 16*1 + 2 + 16*2 + 1 = 51
下記を解く前に、上の例題を確かめてから始めるとよく分かる。
10 進数に直して計算があっているかも確かめること。
指数 (ベキ数) の表示は、** とする。cal_pw.rb
#!/usr/koeki/bin/ruby
# coding: euc-jp
STDERR.printf("指数計算です。底はいくつ?\n")
base = gets.to_i # 底 (base) をしまう変数を base とする
STDERR.printf("指数はいくつ?\n")
exp = gets.to_i # 指数 (exponent) をしまう変数を exp とする
printf("%d の %d 乗を計算しました。答えは %d\n",
base, exp, base ** exp)
0d 100 は変数 base と exponent を 使って、どのように書くことが できるか、base の値を 16, 10 ,2 (進数の底) として、 変数 exponent を 0, 1, 2, ... と増やし、値を調べよ。
0d 100 = a * base ** 0 + b * base ** 1 + .... + c * base ** (exponent - 1) + d * base ** exponent
という形で一般に書くことができる(a, b, c, d ... は base の値を越えない整数)。
割り算の余りは、% で求める。 cal_rem.rb
#!/usr/koeki/bin/ruby
# coding: euc-jp
STDERR.print("余りを出します。割られる数はいくつ?\n")
div = gets.to_i # 割られる数(被除数, dividend)
# を div とする
STDERR.print("割る数はいくつ?\n")
mod = gets.to_i # 割る数(除数, modulus) を mod とする
quot = div / mod # 商 (quotient) を quot とする
rem = dividend % modulus # 余り (remainder) を rem とする
printf("商 は %d で余りは %d です\n", quot, rem)
printf("もとの数は %d でした\n", quot * mod + rem)
なぜ、このプログラムで商が出てくるのか、 手計算で変数に入っているはずの値を追いかけながら、調べよ。
0b 1101 = 1 * 2 ** 0 + 0 * 2 ** 1 + 1 * 2 ** 2 + 1 * 2 ** 3 = 1 + 0 + 4 + 8 = 0d13 などの 2 進数の計算を行うプログラムを作ろう。 cal_bin.rb
#!/usr/koeki/bin/ruby
# coding: euc-jp
STDERR.print("2 進数を計算するよ\n")
STDERR.print("1 桁目から入力し、終了したら q を押してください\n")
n = 1 # 桁数
x = 0 # 10進数の数
base = 2 # 2 進数 (binary)
while true
STDERR.printf("%d 桁目の数はいくつですか: ", n)
m = gets.chomp # n 桁目の数字
if m == "q"
break
else
m = m.to_i
end
x += m * base ** (n-1)
n += 1
end
printf("10 進数に直すと %d になります\n", x)
実際に 0b 1101 をこのプログラムを使って計算し、 0d 13 となることを確かめよ。
割り算の余りを利用して、曜日を当てるプログラムを作ろう。 cal_cal.rb
#!/usr/koeki/bin/ruby
# coding: euc-jp
STDERR.print("5 月の曜日を調べます。日付は?: ")
day = gets.to_i # 日づけをしまう変数
d = ( 1 + day ) % 7 # 2012 年 5 月は火曜日開始。0 は日曜日。
if d == 0
wday = "日" # 曜日を表す変数
elsif d == 1
wday = "月"
elsif d == 2
wday = "火"
elsif d == 3
wday = "水"
elsif d == 4
wday = "木"
elsif d == 5
wday = "金"
else wday = "土"
end
printf("%d 日は %s曜日 です\n", day, wday)
同じ曜日の日付が 7 ずつずれることを使ったプログラムである。 進数変換と同じしくみを使っている。
本講義の定期試験、就職試験等にも出題されるので、 他の本などでも訓練しておくべし。
ヒント: "となりから 10 借りてくる" のは 10 進法、 "となりから 16 借りてくる" のが 16 進法であることを思い出そう。