02回(10/24) | 03回(10/31) | |
---|---|---|
3コマ | 39 | 40 |
4コマ | 44 | 42 |
その他: トラブルなどについては講義中に質問・解決するようにしてください。 またネットワーク絡みのトラブルについては情報処理センターや生協に相談してください。
if や while などの条件部に書く論理式を組み立てるときに使われる論理演算に and / or / not があります。それぞれ、and (論理積)は「かつ」、or (論理和)は「または」、not (論理否定)は「でなければ」に相当します。
|
|
参考: ベン図 in ウィキペディア
また and は && 、 or は || 、not は ! と書くこともできます(基本的には好みの問題、文法的には若干の違いがありますが)。
複雑な論理式では演算の順序を明確にするために括弧を使いましょう。 たとえば ( A and B ) or C と A and ( B or C ) は異なる論理式です。
例1: x は y 以上 → x => y あるいは not (x < y)
例2: x が y より小さく、かつ、 x2 が y より大きい。 → x < y and x**2 > y
例3: x と y が等しいか、x が負値かつ x2 と y2 が等しい → x == y or ( x < 0 and x**2 == y**2 )
ある操作について名前を付けます。
def funname(var1, var2, ...) commands end
funname が関数(メソッド)名、var1 を仮引数(カリヒキスウ)といいます。仮引数はゼロ個でも1個でも複数個でもかまいません。 また関数名は英小文字(a-z)で始まる英数字と '_' からなる文字列です(このあたり厳密には嘘なので 正確なところはリファレンスマニュアルを参照してください)。
関数は funname(e1, e2, ...) という形で呼出されます(関数呼出し)。このとき e1, e2 を引数(ヒキスウ)と呼びます。引数の数は関数定義の仮引数の数と一致します。
def square(n) # 2乗を計算する関数の定義 return n**2 end puts square(10) # 関数呼出し puts square(20) # 関数呼出し
return n でその関数を終了して値( n )を返します。 関数内の最後(endの直前)まで実行された場合は 最後の文を実行して、その値を返します。
def sum_of_squares(x,y) # x^2 + y^2 を計算する関数の定義 return x*x + y*y end puts sum_of_squares(3,4)
同じ値を返す関数でも定義の方法は複数あることが普通です。
def fact1(n) # 階乗の計算(1) s = 1 for i in 1 .. n s *= i end return s end def fact2(n) # 階乗の計算(2) ... 再帰的定義 if (n > 0) return n * fact2(n-1) else return 1 end end puts fact1(10) # 10! puts fact2(10) # 10! puts fact1(fact2(5)) # (5!)! = 120!
---------------------------------------------------------------------- fact1(5) s = 1 i = 1 s *= i # s は 1 i = 2 s *= i # s は 1*2 = 2 i = 3 s *= i # s は 1*2*3 = 6 i = 4 s *= i # s は 1*2*3*4 = 24 i = 5 s *= i # s は 1*2*3*4*5 = 120 return s # fact1(5) の値は 120 となる fact2(5) 5 * fact2(4) # n = 5 > 0 だから 5 * 4 * fact2(3) # n = 4 > 0 だから 5 * 4 * 3 * fact2(2) # n = 3 > 0 だから 5 * 4 * 3 * 2 * fact1(1) # n = 2 > 0 だから 5 * 4 * 3 * 2 * 1 * fact1(0) # n = 1 > 0 だから 5 * 4 * 3 * 2 * 1 * 1 # n = 0 なので fact1(n) = 1 5 * 4 * 3 * 2 * 1 5 * 4 * 3 * 2 5 * 4 * 6 5 * 24 120 # fact2(5) の値は 120 となる ----------------------------------------------------------------------
変数のスコープ: 仮引数や関数内で定義された変数は、関数の外からは見えません。 関数外や別関数内に同名の変数があっても、それは無関係です。
def f(x) y = x+1 return y end x=5 y=10 puts x + f(y)
問2: 2つの数を引数として大きい方の値を返す関数 max と、小さい方の値を返す関数 min を定義してください。
def max(x,y) if x > y return x else return y end end def min(x,y) if x < y return x else return y end end
問3: 引数 n (> 0)に対して m2 < n となる最大の m を返す関数 isquare を定義してみましょう。
def isquare(n) i=0 while true if (i+1)**2 > n return i end i += 1 end end puts isquare(99)
問4: Fibonacci 数列の定義は以下のとおりです。
def fib1(n) if n==0 return 0 elsif n==1 return 1 else return fib1(n-1) + fib1(n-2) end end for n in 0 .. 5 puts fib1(n) end
---------------------------------------------------------------------- fib1(5) fib1(4) + fib1(3) fib1(3) + fib1(2) + fib1(2) + fib1(1) fib1(2) + fib1(1) + fib1(1) + fib1(0) + fib1(1) + fib1(0) + fib1(1) fib1(1) + fib1(0) + fib1(1) + fib1(1) + fib1(0) + fib1(1) + fib1(0) + fib1(1) 1 + 0 + 1 + 1 + 0 + 1 + 0 +1 5 ----------------------------------------------------------------------
def fib2(n) a = 1 # F(1) b = 0 # F(0) while n > 0 # n 回ループする t = a a += b b = t n -= 1 end return b end for n in 0 .. 5 puts fib2(n) end # コメント: Ruby では a, b = a+b, a という多重代入も可能だかここでは触れない
問7: for n in 0 .. 25 くらいで fib1 と fib2 の計算時間を比較してみましょう。
問8: fib2(n) で Fn が計算できることの証明。
Vn = ( | Fn+1 | ) |
Fn |
R = | ( | 1 | 1 | ) |
1 | 0 |
( | Fn+1 | ) | = | ( | 1 | 1 | ) ( | Fn | ) |
Fn | 1 | 0 | Fn-1 |
( | Fn+1 | ) | = | ( | 1 | 1 | ) | n |
( | F1 | ) |
Fn | 1 | 0 | F0 |
V0 = | ( | F1 | ) | = | ( | 1 | ) |
F0 | 0 |
a = 1 b = 0と変数 a, b の値を代入後に a, b を(同時に) a+b, a で置き換える 計算を n 回くりかえすと a = Fn+1 , b = Fn となっている。
このように「アルゴリズム」が異なると計算時間などが大幅に違ってくることがあります。 したがって、ある問題を解くときにより効率的なアルゴリズムを適用するのが賢い方法です。
def a(x,y) if x==0 then return y+1 elsif y==0 then return a(x-1,1) else return a(x-1,a(x, y-1)) end end def f0(n) return a(0,n) end def f1(n) return a(1,n) end def f2(n) return a(2,n) end def f3(n) return a(3,n) end def f4(n) return a(4,n) end