Problem 2

Problem 2

module Problem_0002

(*
【問題】
フィボナッチ数列の項は前の2つの項の和である。
 最初の2項を 1, 2 とすれば、最初の10項は以下の通りである。
 「1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ...」
数列の項の値が400万を超えない範囲で、偶数値の項の総和を求めよ。
*)
///フィボナッチ関数
/// min: 初期値(型定義用)
/// max: フィボナッチ数の最大値
let fib min max =
    let rec fibRT = function
        | [] | [_] -> fibRT (min :: _arg1)
        | _ ->
            if max < _arg1.Head then _arg1
            else fibRT((_arg1.[0] + _arg1.[1]) :: _arg1)
    fibRT []

let run () =
    fib 1M 4000000M
        |> List.filter (fun x -> x % 2M = 0M)
        |> List.fold (+) 0M


書き直したコード1(何かがおかしいかも?)

let fib n m =
    Seq.unfold (fun state ->
        if (snd state > m) then None
        else Some(fst state + snd state, (snd state, fst state + snd state))) (n, n)

let run () =
    fib 1M 4000000M
        |> Seq.filter (fun x -> x % 2M = 0M)
        |> Seq.fold (+) 0M


書き直したコード2

//52~53ms 4613732M
let fib n m =
    Seq.unfold (fun (n1, n2) ->
        if (n1 < m) then Some(n1, (n2, n1 + n2))
        else None) (n, n)

let run () =
    fib 1M 89M
        |> Seq.filter (fun x -> x % 2M = 0M)
        |> Seq.fold (+) 0M


書き直したコード3

let fibInfinity =
    Seq.initInfinite ((+)0)
    |> Seq.scan (fun (x,y) n -> (y,x+y)) (0I,1I)
    |> Seq.map (snd)

let run () =
//    fib 1M 89M
    fibInfinity
    |> Seq.takeWhile ((>=)4000000I)
    |> Seq.filter (fun x -> x%2I=0I)
    |> Seq.sum


■計算式ビルダ
使ってる意味がないけれど、使い方を覚えるために・・・

type FibBuilder() =
    let fibSeq =
        Seq.initInfinite (fun x -> x)
        |> Seq.scan(fun (x,y) n -> (y,x+y)) (0,1)
        |> Seq.map(snd)
        |> Seq.cache
    member this.Yield (x:int) = if x%2=0 then x else 0
    member this.For (v,f) =
        let max = v |> Seq.max
        fibSeq
        |> Seq.takeWhile ((>=)max)
        |> Seq.map(fun x -> f x)
    member this.Run v = v |> Seq.sum
let fib = FibBuilder()

let run() =
    fib { for x in 0..(4000000-1) -> x }
      • -