【发布时间】:2010-11-08 22:06:35
【问题描述】:
这实际上是 F# 中 Project Euler Problem 14 的解决方案。但是,在尝试计算更大数字的迭代序列时,我遇到了 System.OutOfMemory 异常。如您所见,我正在编写带有尾调用的递归函数。
我遇到了 StackOverFlowException 的问题,因为我在 Visual Studio 中进行调试(禁用尾调用)。我已经记录了in another question。在这里,我在发布模式下运行 - 但是当我将它作为控制台应用程序运行时(在具有 4gb ram 的 windows xp 上),我会出现内存不足的异常。
我真的不知道我是如何将自己编码到这个内存溢出中并希望有人能以我的方式向我展示错误。
let E14_interativeSequence x =
let rec calc acc startNum =
match startNum with
| d when d = 1 -> List.rev (d::acc)
| e when e%2 = 0 -> calc (e::acc) (e/2)
| _ -> calc (startNum::acc) (startNum * 3 + 1)
let maxNum pl=
let rec maxPairInternal acc pairList =
match pairList with
| [] -> acc
| x::xs -> if (snd x) > (snd acc) then maxPairInternal x xs
else maxPairInternal acc xs
maxPairInternal (0,0) pl
|> fst
// if I lower this to like [2..99999] it will work.
[2..99999]
|> List.map (fun n -> (n,(calc [] n)))
|> List.map (fun pair -> ((fst pair), (List.length (snd pair))))
|> maxNum
|> (fun x-> Console.WriteLine(x))
编辑
根据答案给出的建议,我重写了使用惰性列表并使用 Int64。
#r "FSharp.PowerPack.dll"
let E14_interativeSequence =
let rec calc acc startNum =
match startNum with
| d when d = 1L -> List.rev (d::acc) |> List.toSeq
| e when e%2L = 0L -> calc (e::acc) (e/2L)
| _ -> calc (startNum::acc) (startNum * 3L + 1L)
let maxNum (lazyPairs:LazyList<System.Int64*System.Int64>) =
let rec maxPairInternal acc (pairs:seq<System.Int64*System.Int64>) =
match pairs with
| :? LazyList<System.Int64*System.Int64> as p ->
match p with
| LazyList.Cons(x,xs)-> if (snd x) > (snd acc) then maxPairInternal x xs
else maxPairInternal acc xs
| _ -> acc
| _ -> failwith("not a lazylist of pairs")
maxPairInternal (0L,0L) lazyPairs
|> fst
{2L..999999L}
|> Seq.map (fun n -> (n,(calc [] n)))
|> Seq.map (fun pair -> ((fst pair), (Convert.ToInt64(Seq.length (snd pair)))))
|> LazyList.ofSeq
|> maxNum
解决问题。不过,我也想看看殷朱的解决方案,哪个更好。
【问题讨论】:
-
正如@Brian 指出的,Seq 更适合这个问题。事实上,在解决了 Project Euler 中的前 45 个问题后,我发现几乎所有问题都最适合基于 Seq 的解决方案。如果您有兴趣,这里是我对问题 14 的解决方案:projecteulerfun.blogspot.com/2010/05/…(当然,您可能希望等到您的解决方案满意后再进行比较,或者您可能已经满足使用您的算法,但想看看基于 Seq 的实现的外观如何)。
-
警告,除了 OutOfMemoryException 之外,您的解决方案至少还有一个其他问题,查看我的解决方案可能会被破坏。
标签: recursion f# out-of-memory tail-recursion