Это на самом деле решение Project Euler Problem 14 в F #. Тем не менее, я запускаю исключение System.OutOfMemory при попытке вычислить итеративную последовательность для больших чисел. Как вы можете видеть, я пишу рекурсивную функцию с хвостовыми вызовами.F # System.OutOfMemoryException с рекурсивным вызовом
У меня возникла проблема с StackOverFlowException, потому что я отлаживал визуальную студию (которая отключает хвостовые вызовы). Я зарегистрировал это in another question. Здесь я запускаюсь в режиме выпуска, но я получаю исключения из памяти, когда запускаю это как консольное приложение (на Windows XP с 4 ГБ оперативной памяти).
Я действительно затрудняюсь понять, как я закодировал себя в этом переполнении памяти. & надеясь, что кто-то может показать мою ошибку в моих путях.
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))
EDIT
Учитывая предложения через ответы, я переписал использовать ленивый список, а также использовать 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 лучше подходит для этой проблемы. Действительно, проработав первые 45 проблем в Project Euler, я обнаружил, что почти все они лучше всего подходят для решений на базе Seq. Если вам интересно, вот мое решение проблемы 14: http://projecteulerfun.blogspot.com/2010/05/problem-14-which-starting-number-under.html (конечно, вы можете подождать до сравните до тех пор, пока вы не удовлетворитесь своей удовлетворенностью или не окажетесь в том месте, где вы довольны своим алгоритмом, но хотели бы посмотреть, как выглядит реализация на основе Seq). –
предупреждение, есть еще одна проблема помимо OutOfMemoryException с вашим решением, которое может быть испорчено, глядя на мое решение. –