Problem 2

フィボナッチ数列の項は前の2つの項の和である。最初の2項を 1, 2 とすれば、最初の10項は以下の通りである。

1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ...

数列の項が400万を超えない範囲で、偶数の項の総和を求めよ。

Problem 2 - PukiWiki

問題の意味を理解するのにやたら時間を要したというアホすぎる罠。暫く数学的な表現とは無縁の世界に逃避してたからな…

Ruby

sum = 0
fib = [1, 2]

while fib.last < 4000000
  if fib.last%2 == 0 then
    sum += fib.last
  end
  fib = [fib.last, fib[0]+fib[1]]
end

puts sum

何の工夫もない。


ここでおもむろにWikipediaでフィボナッチ数を調べてみると、

Fm が偶数となるのは m が 3 の倍数となるときと一致する。

フィボナッチ数 - Wikipedia

これか、これなのか?という事でやってみる。
Wikipedia見たついでにFmはこれで出そう。

Fn の正確な整数値は以下の式で与えられる。

F_n = \left\lfloor {\phi^n \over \sqrt{5}} + \frac{1}{2} \right\rfloor
\phi \equiv \frac{1+\sqrt{5}}{2} \simeq 1.618033988749895

フィボナッチ数 - Wikipedia
def fib(n)
  ((((1+Math.sqrt(5))/2)**n)/Math.sqrt(5)+0.5).floor
end

sum = 0
k = 3

while fib(k) < 4000000
  sum += fib(k)
  k += 3
end

puts sum

できた。しかしもはやコードを見ただけでは何をやっているのか分からない。

R

sum <- 0
fib <- c(1, 2)

while (fib[2] < 4000000) {
  if(fib[2]%%2 == 0) {
    sum <- sum + fib[2]
  }
  fib <- c(fib[2], fib[1]+fib[2])
}

sum

Ruby版の最初のを書き直しただけであった。これは酷い。でもこれどう書き直せばいいかな…

Haskell

fib n = floor ((phi**n)/(sqrt 5) + 0.5)
  where
    phi = (1+(sqrt 5))/2

main = print $ sum [x | x <- takeWhile (< 4000000) $ map fib [3,6..]]

う〜ん。変に公式使わないで普通に書いた方が綺麗に書けた気がする。
こうか。

fib = 1:2:zipWith (+) fib (tail fib)

main = print $ sum [x| x <- takeWhile (< 4000000) fib, even x]

takeWhile (< 4000000)がめんどいなーと思って[x| x <- fib, x < 4000000 && even x]などと書くと帰ってこなくなる。Haskellよくわかりません。