Ruby プログラミングの基礎: 条件分岐,繰り返し,配列,文字列
今日の内容
関数
コンピュータとの対話 (復習)
- ターミナルの起動
- irb の起動
- プログラムの入力
bmi の関数を使った定義
irb(main):001:0> def bmi(height, weight) # 関数名 bmi,関数引数 height, weight
irb(main):002:1> weight / ( height / 100.0 ) ** 2 # bmi の計算式
irb(main):003:1> end
=> nil
- 「#」という記号が現れるが,これは以下がコメントであることを示している.
コメントはプログラムとは見なされず,プログラムの説明や注釈,覚書を書くために使われる.
関数の実行
irb(main):004:0> bmi(162.5, 72.0)
=> 27.2662721893491
irb(main):005:0> bmi(180.0, 75.0)
=> 23.1481481481481
irb(main):006:0> height = 162.5
=> 162.5
irb(main):007:0> weight = 72.0
=> 72.0
irb(main):008:0> bmi(height, weight)
=> 27.2662721893491
irb(main):006:0> height = 180.0
=> 180.0
irb(main):007:0> weight = 75.0
=> 75.0
irb(main):008:0> bmi(height, weight)
=> 23.1481481481481
東工大の教育用計算機システム Windows 端末のファイルシステム
C ドライブ
- Windows 端末がローカルに持つファイルシステム
- ユーザのホームディレクトリは,
C:\User\$USER
となる.ここで,$USER は各自のアカウントを表わすものとする.
- C:\User\$USER の下にいろいろなディレクトリ,ファイルがある.
- C:\User\$USER の内容は,
- ログイン時に TSUBAME 2.0 のホームディレクトリからダウンロードされ,
- ログアウト時に TSUBAME 2.0 のホームディレクトリにアップロード,保存
される.
- 現システムでは,Windows が落ちたり,TSUBAME 2.0 へのアップロードでトラブルがあると,
Windows 端末の C ドライブに作ったファイルが失われる.
Z ドライブ
- TSUBAME 2.0 上の Windows 用ファイルシステム
- Z ドライブのルートディレクトリは,TSUBAME 2.0 上の各自のホームディレクトリが対応.
- 利用している Windows 端末からネットワーク越しに TSUBAME 2.0 にアクセスする.
Cygwin の環境設定
- Windows 上で Unix (Windows と異なる代表的なオペレーティングシステム) のコマンドを利用出来るソフトウェア
- コンピュータをより高度に利用するには是非知っておきたいもの.
- /cygdrive/c は Windows の C ドライブ,/cygdrive/z は Windows の Z ドライブに対応する.
[演習 3.1]
- Cygwin Bash Shell でコマンド pwd を実行し,/cygdrive/z と表示されたら以下を実施する必要はない.
- Cygwin Bash Shell を終了しなさい.
- Cygwin の環境をセットアップするファイルをダウンロードし,デスクトップに置きなさい.
- デスクトップに置いたファイルをダブルクリックして実行しなさい.
- Cygwin Bash Shell を動かしなさい.
- コマンド pwd を実行し,/cygdrive/z と表示されることを確認しなさい.
プログラムをエディタを使って書きファイルに保存
ファイルに保存する意義
- エディタに打ち込んだプログラムをコピーして,irb にペーストしても良いが,プログラムが長くなったら面倒である.
- ファイルに保存すればそのプログラムを何度でも使える.
- Ruby のプログラムは同じ場所に保存しておいた方が便利なので,例えばホームディレクトリの下に ruby という名のディレクトリを作ろう.
ディレクトリ (フォルダ) の作り方
- 一度 irb を終了しよう.
- Ruby のプログラムを保存するディレクトリを /cygdrive/z の中に作ろう.
- mkdir は新たにディレクトリを作る命令である.
上の例の場合には,現在いるディレクトリの下に ruby という名のディレクトリが出来る.
- 今どのディレクトリにいるのかは,pwd というコマンドを打っても分かる.
- 今いるディレクトリに,どういうディレクトとファイルがあるかは,ls というコマンドを打つことで分かる.
$ ls
_EDU lecture public_html
[演習 3.2]
- ruby のプログラムを入れるディレクトリ ruby を作ってみよう.
ディレクトリの移動
- 作業ディレクトリを移動するには,cd というコマンドを使う.
- 作業ディレクトリに ruby というディレクトリがあれば,これで ruby という名のディレクトリに移動できる.
- 親のディレクトリに戻るには,以下のようにする.
[演習 3.3]
- ruby のプログラムを入れるディレクトリに移動しよう.
エディタを使う
- 長いプログラムを irb に直接書くと打ち間違いなどで大変なことになる.
=> テキストエディタを使ってプログラムを書く.
=> 打ち間違えても直すのが簡単.
- テキストエディタは,TeraPad でも良いが,emacs (Medow) の方が Ruby プログラミングを支援するモードが充実しているので便利.
- Medow を使う場合には,初めて使う時にMeadowのRubyモードを利用出来るようにする設定を行う.
[演習 3.4]
- テキストエディタを起動し,ファイル名 bmi.rb を指定して,bmi の関数を使った定義を打ち込んでみよう.
プログラムをファイルに保存
- プログラムを書いたファイルに名前を付け,Ruby のプログラムを入れるディレクトリに保存する.
Emacs の場合にはプログラムを書く前にファイルを作成して,プログラムを書く.
- Ruby のプログラムは,bmi.rb のように名前の後に「.rb」を付ける.
これをファイル拡張子といい,Ruby のプログラムであることを示している.
Emacs の場合には .rb が付いたファイルを読み込むと,Ruby のプログラムであると認識し,Ruby を支援するモードになる.
[演習 3.5]
- bmi のプログラムを bmi.rb という名前のファイルとして,Ruby のプログラムを入れるディレクトリに保存しよう.
irb を再び動かす
- irb を Ruby のプログラムがあるディレクトリで動かす.
プログラムをファイルから読み込む
irb(main):001:0> load("./bmi.rb")
=> true
irb(main):002:0> bmi(162.5, 73.0)
=> 27.6449704142012
- load はプログラムを読み込む関数で,ダブルクォートで囲まれた部分にファイル名を書く.
./ の部分は現在 irb が動いているディレクトリを意味している.
- プログラムを読み込むと,関数を呼び出してすぐに実行できる.
[演習 3.6]
- bmi.rb を irb に読み込んで,関数 bmi を実行しなさい.
条件分岐
2次方程式の解法
# q_eq.rb
# 2次方程式 (quadratic equation) a*x**2+b*x+c=0 を解く関数
include Math # 数学関数を使えるようにする
def d(a,b,c) # 判別式計算関数
b ** 2 - 4 * a * c # 判別式の計算
end # 関数定義の終わり
def q_eq_solution1(a,b,c) # 方程式の解1を求める関数
d = d(a,b,c) # 判別式の計算結果を変数 d に保存
if d >= 0 # 判別式 d(a,b,c) が0以上か?
(-b + sqrt(d)) / (2 * a) # d(a,b,c) が0以上なら計算
end # if 文の終わり
end # 関数定義の終わり
def q_eq_solution2(a,b,c) # 方程式の解2を求める関数
d = d(a,b,c)
if d > 0
(-b - sqrt(d)) / (2 * a)
end
end
def q_eq(a,b,c) # 方程式の解を求める関数
d = d(a, b, c)
if d > 0 # 判別式が0以上のとき
[q_eq_solution1(a,b,c), q_eq_solution2(a,b,c)] # 2つの解を計算
elsif d == 0 # 判別式が0と等しいとき
[q_eq_solution1(a,b,c)] # 重解を計算
else # それ以外のとき
nil # 解がない
end
end
[演習 3.7]
- 2次方程式を解くプログラムを作成してファイルに保存し,irb で実行しなさい.
if 文の他の書き方
# sign.rb
def sign(x)
if x < 0
-1
else
if 0 < x
1 # x < 0 でなく 0 < x のとき
else
0 # x < 0 でなく 0 < x でないとき
end
end
end
[演習 3.8]
- 上記の関数 sign はどういう動きをする関数か予想しなさい.
- 次にプログラムを作成し,予想があっているか確認しなさい.
[問題 3.1]
- 3つの数の最大値を求める関数 max3 を作りなさい.
繰り返し
最大公約数を求める
# gcd_s.rb
# 最大公約数を単純な方法で求めるプログラム
def gcd_s(x,y) # 関数 gcd_s の定義
if x > y # x, y のうち大きくない方を n に設定
n = y
else
n = x
end
k = 1
while k <= n # k が n 以下なら繰り返す:
if x % k == 0 && y % k == 0 # x と y が k で割り切れるか判定
ans = k # k が x と y の公約数のときに ans に設定
end
k = k + 1 # k の値を 1 増やす
end
ans # 答えとして ans の値を返す
end
計算の途中結果を表示
- プログラムを書いたときに,思うとおりの計算結果にならないときも多い.
そのようなときには,計算の途中結果を表示させると間違いに気が付くときがある.
- 計算の途中結果を表示させるには print という関数を使う.
- 以下はユークリッドの互除法の計算を逐次表示するプログラムである.
# gcd_s_p.rb
# 最大公約数を単純な方法で求めるプログラム
def gcd_s(x,y) # 関数 gcd_s の定義
if x > y # x, y のうち大きくない方を n に設定
n = y
else
n = x
end
k = 1
while k <= n # k が n 以下なら繰り返す:
if x % k == 0 && y % k == 0 # x と y が k で割り切れるか判定
ans = k # k が x と y の公約数のときに ans に設定
print "k = ", k, "\n" # 公約数を表示
# k = という文字列の後に k の値を表示.
# \n という文字列は改行を行う.
end
k = k + 1 # k の値を 1 増やす
end
ans # 答えとして ans の値を返す
end
- gcd_s_p.rb を実行すると次のようになる.
irb(main):002:0> load("./gcd_s_p.rb")
=> true
irb(main):003:0> gcd_s_p(100, 50)
k = 1
k = 2
k = 5
k = 10
k = 25
k = 50
=> 50
[問題 3.2](collatz 予想)
- 偶数なら2で割り,奇数なら3倍して1を足す.
これを繰り返すといつか1になる.(ただし証明はされていない.)
- この計算の途中結果を表示しながら,何回の計算で1になるかを関数の値として返すような関数 collatz を作成しなさい.
配列
フィボナッチ数の計算
# fib.rb: フィボナッチ数を最初からn個計算するプログラム
def fib(n)
fib = Array.new(n) # 長さ n の配列 fib を作る.
fib[0] = 1 # 配列 fib の第0要素 (1番目) に1を代入.
fib[1] = 1 # 配列 fib の第1要素 (2番目) に1を代入.
for i in 2..n-1 # i を2から n-1 まで順に動かして,
fib[i] = fib[i-1] + fib[i-2]
# 配列 fib の第 i-1 要素と第 i-2 要素を足して第 i 要素に代入.
end
fib # 配列 fib を結果として返す.
end
[演習 3.9]
- フィボナッチ数の計算 fib.rb をファイルに保存し irb で実行しなさい.
[問題 3.3]
- Collatz 予想の計算途中経過を配列に残し,その配列を返す関数を作りなさい.
Ruby では配列の長さが不足すると,自動的に追加される.
文字列の処理
文字列をつなげるプログラム
def add_string(str1,str2)
s = str1 + str2 # 文字列 str1 と文字列 str2 をつなげて s に代入
end
[演習 3.10]
- 上記のプログラムを add_string.rb に保存し,irb で実行して文字列がつながることを確認しなさい.
部分文字列を返す
def sub_string(str, m, n)
if m >= 0 && n >= 0 && m < str.length && n < str.length
# m, nが文字列strの範囲内かを判定.
str[m..n]
# 文字列strのうち,第m要素から第n要素までの文字列を返す.
end
end
irb(main):116:0> string = "Computer Science"
=> "Computer Science"
irb(main):117:0> sub_string(string,3,10)
=> "puter Sc"
irb(main):118:0> sub_string(string,9,9)
=> "S"
[演習 3.11]
- 上記のプログラムを sub_string.rb に保存し,irb で実行して文字列の一部を取り出せる事を確認しなさい.
次回の予告
- 次回の授業は教室で行います.
- 来週の授業の主な内容 (予定)
- アルゴリズムと計算量
- ユークリッドの互除法
- フィボナッチ数の計算
- 計算量の考え方
2012年10月5日作成
2012年10月14日改訂
2012年10月18日訂正
伊知地 宏
Copyright (C) Hiroshi Ichiji, 2012. All rights reserved.