Ich habe einige leistungsabhängige Code auf einem Node.js-Server, der Kombinationen zählen muss. Von this SO answer ich diese einfache rekursive Funktion für die Berechnung verwendete n wählen k:Effiziente Berechnung von n Wählen Sie k in Node.js
function choose(n, k) {
if (k === 0) return 1;
return (n * choose(n-1, k-1))/k;
}
Dann, da wir alle Iteration wissen fast immer schneller als Rekursion ist, schrieb ich diese Funktion auf der Grundlage der multiplicative formula:
function choosei(n,k){
var result = 1;
for(var i=1; i <= k; i++){
result *= (n+1-i)/i;
}
return result;
}
Ich lief ein paar benchmarks auf meiner Maschine. Hier sind die Ergebnisse von nur einem von ihnen:
Recursive x 178,836 ops/sec ±7.03% (60 runs sampled)
Iterative x 550,284 ops/sec ±5.10% (51 runs sampled)
Fastest is Iterative
Die Ergebnisse konsequent zeigten, dass die iterativen Verfahren sind in der Tat etwa 3 bis 4 mal schneller als die rekursive Methode in Node.js (zumindest auf meinem Rechner).
Dies ist wahrscheinlich schnell genug für meine Bedürfnisse, aber ist es eine Möglichkeit, es schneller zu machen? Mein Code muss diese Funktion sehr häufig aufrufen, manchmal mit ziemlich großen Werten von n
und k
, je schneller desto besser.
EDIT
Nach ein paar Tests mit le_m ist und Mikes Lösungen laufen, stellt sich heraus, dass zwar beide deutlich schneller als das iterative Verfahren I vorgeschlagen, Mike Methode Pascals Dreieck mit scheint schneller zu sein leicht als le_m Logbuch Tabellenmethode. um 26-28 mal schneller als die iterativen Verfahren in meinen Tests
Recursive x 189,036 ops/sec ±8.83% (58 runs sampled)
Iterative x 538,655 ops/sec ±6.08% (51 runs sampled)
LogLUT x 14,048,513 ops/sec ±9.03% (50 runs sampled)
PascalsLUT x 26,538,429 ops/sec ±5.83% (62 runs sampled)
Fastest is PascalsLUT
Die logarithmische aufblick Methode wurde und das Verfahren Pascals Dreieck mit war etwa 1,3 bis 1,8-mal schneller als die logarithmische Methode nachschlagen.
Bitte beachte, dass ich le_m Vorschlag der Pre-Berechnung der Logarithmen mit höherer Genauigkeit gefolgt mathjs verwenden, konvertiert sie dann wieder zu den regulären JavaScript Number
s (was immer double-precision 64 bit floats sind).
Memoization kann die schnellste Wahl sein, wenn Platz nicht Ihr Interesse ist. – Godfather
Aus dem Kommentar zu der Antwort, die Sie verlinkt haben und von der [Wikipedia-Seite] (https://en.wikipedia.org/wiki/Binomial_coefficient#Factorial_formula): 'if (k> n/2) return Wählen Sie (n, nk) ; '- was hilft, wenn sowohl 'n' als auch 'k' groß sind, aber die zusätzliche Verzweigung könnte die Gesamtausführung verlangsamen. – Bergi
@Godfather @NanoWizard und wenn Sie nicht den Platz haben, um die choeiti Ergebnisse zu momoize, können Sie gute Leistungssteigerungen erhalten, indem Sie die faktorials momoisieren. Sie können sogar eine dynamische Programmiertechnik haben, um die faktorielle 'fact (n) = max_known_fact_value (n) * [i für evey int für max_known_fact_int (n) bis n]' zu berechnen, die erhebliche Zeit sparen würde – gbtimmon