何だか気分的に煮詰まってしまったので、 気分転換に SICP の問題でも解いてみる。 C++で解く という強者もいらっしゃるようだが、 私は屁垂れなので、 Python でやってみる。 疲れた時にわざわざ蛇の道を歩むこともなかろう... SICP in other languages にPythonの例もあるみたいだが、 それは見なかったことにする。
Exercise 1.3. 三つ引数を取って、大きい方の二つの数字の自乗の和を求める関数を書け。 これぐらい簡単でないと頭は休まらないよな。
def f(a, b, c): l = [a, b, c] l.remove(min(l)) return sum([x * x for x in l])
思わずbrute-forceでやってしまったが、
def f(a, b, c): return sum([x * x for x in (max(a, b), max(min(a, b), c))])
これと比べて、速度差なんて出るんだろうか。
Exercise 1.11.
n
が3未満なら、f(n) = n
で、
3以上なら、f(n) = f(n - 1) + 2f(n - 2) + 3f(n - 3)
となる関数を、再帰と繰り返しの両方で書け。
再帰だとそのまんまだ。Pythonは簡単だ。
def f(n): if n < 3: return n return f(n-1) + 2*f(n-2) + 3*f(n-3)
繰り返し。無意味に generator を使ってみる。
def f(n): def g(): a = [] while 1: l = len(a) if l < 3: a.insert(0, l) else: a.insert(0, a[0]+2*a[1]+3*a[2]) a.pop() yield a[0] i = g() for c in xrange(n - 1): i.next() return i.next()
全然分かりやすくもならないし、速くもならないな。 ベタで書いた方がマシ。
def f(n): if n < 3: return n a = [2, 1, 0] for i in xrange(n-2): a.insert(0, a[0]+2*a[1]+3*a[2]) a.pop() return a[0]
Exercise 1.16. 自乗しまくって、対数ステップ数で指数を計算する関数を繰り返しで書け。
def f(b, n): a = 1 while n: if n % 2: a *= b n -= 1 else: b *= b n /= 2 return a
ヒントそのまんまで書けてしまって、ちっとも面白くない。 だからと言って、これより効率的な方法も思い付かないのがくやしい。
Exercise 1.32.
sum
とか product
を一般化するのに、
accumulator
を書け。
再帰と繰り返しの両方で。
繰り返し。
def accumulate(combiner, null_value, term, a, next, b): r = null_value while a <= b: r = combiner(r, term(a)) a = next(a) return r
再帰。
def accumulate_r(combiner, null_value, term, a, next, b): if a > b: return null_value return combiner(term(a), accumelate_r(combiner, null_value, term, next(a), next, b))
当然再利用できる。
def sum(term, a, next, b): return accumulate(lambda x, y: x + y, 0, lambda x: x, a, next, b) def product(term, a, next, b): return accumulate(lambda x, y: x * y, 1, lambda x: x, a, next, b)
なんか本当にそのまんまだよな。
Exercise 1.37. k-term finite continued fractionを書け。 再帰と繰り返しの両方で。 これって日本語で何て言うんだっけ? k次有限連分数?
繰り返し。ケツから行くだけ。
def cont_frac(n, d, k): r = 0.0 for i in xrange(k, 0, -1): r = n(i) / (d(i) + r) return r
再帰。 うまい手が思い付かなかったので、 中に関数作って、変数を余分に足してしまった。 もうちょっとマシな方法はある?
def cont_frac_r(n, d, k): def f(i): if k == i: return n(k) / d(k) else: return n(k) / (d(k) + f(i + 1)) return f(0)
この辺で飽きてしまった。 はっきり言って、Pythonでやると簡単過ぎて、 何のネタにもならないようである。
SICPを見るのって久しぶりだったけれど、 案外これに載っているネタって、 Lispじゃないと意味を為さない部分が多いんだなあ。