Ich habe diesen Code in F #, der die kleinste positive Zahl findet, die durch alle Zahlen von 1 bis 20 teilbar ist. Es dauert 10 Sekunden.F # Leistungsunterschied zwischen Tail-Rekursion und Seq-Bibliothek
let isDivisableByAll num (divisors: int[]) = Array.forall (fun div -> num % div = 0) divisors
let minNumDividedBy (divisors: int[]) =
let rec minNumDividedByAll stopAt acc =
if acc >= stopAt then 0
else if isDivisableByAll acc divisors then acc
else minNumDividedByAll stopAt (acc + 1)
minNumDividedByAll 400000000 1
minNumDividedBy [|1..20|]
Also dachte ich, ich könnte es eleganter machen, weil ich weniger Code bevorzuge und schrieb folgendes.
let answer = { 1..400000000 }
|> Seq.tryFind (fun el -> isDivisableByAll el [|1..20|])
Es dauerte 10 Minuten! Ich konnte den großen Unterschied nicht erklären, da Sequenzen faul sind. Um zu untersuchen, schrieb ich eine Imperativschleife.
let mutable i = 1
while i < 232792561 do
if isDivisableByAll i [|1..20|] then
printfn "%d" i
i <- i + 1
Es dauerte 8 Minuten. Deshalb ist es auch nicht die Sequenz, richtig? Also, warum ist die anfängliche Funktion so schnell? Es kann nicht vermieden werden, den Stack aufgrund der Schwanzrekursion aufzubauen, oder? Weil ich nicht erwarten würde, dass ein beträchtlicher Stapel, wenn überhaupt, in den langsamen Beispielen entweder gebaut wird.
Es macht nicht viel Sinn für mich, kann mir jemand sagen?
Vielen Dank.
Im zweiten Beispiel weisen Sie bei jeder Iteration ein neues Array zu. Über diese vielen Iterationen muss es sich addieren. Versuchen Sie zuerst, das Array zu erstellen und dann die Iterationen auszuführen. –
faul = nicht schnell :-) – s952163
Natürlich gibt es einen viel einfacheren Weg, dies mit einer algorithmischen Änderung zu tun. –