Auf der Suche nach einer wirklich schnellen Implementierung der Fakultätsfunktion in JavaScript. Irgendwelche Vorschläge?
Auf der Suche nach einer wirklich schnellen Implementierung der Fakultätsfunktion in JavaScript. Irgendwelche Vorschläge?
Antworten:
Sie können nach (1 ... 100) suchen! auf WolframAlpha , um die faktorielle Sequenz vorab zu berechnen.
Die ersten 100 Zahlen sind:
1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800, 39916800, 479001600, 6227020800, 87178291200, 1307674368000, 20922789888000, 355687428096000, 6402373705728000, 121645100408832000, 2432902008176640000, 51090942171709440000, 1124000727777607680000, 25852016738884976640000, 620448401733239439360000, 15511210043330985984000000, 403291461126605635584000000, 10888869450418352160768000000, 304888344611713860501504000000, 8841761993739701954543616000000, 265252859812191058636308480000000, 8222838654177922817725562880000000, 263130836933693530167218012160000000, 8683317618811886495518194401280000000, 295232799039604140847618609643520000000, 10333147966386144929666651337523200000000, 371993326789901217467999448150835200000000, 13763753091226345046315979581580902400000000, 523022617466601111760007224100074291200000000, 20397882081197443358640281739902897356800000000, 815915283247897734345611269596115894272000000000, 33452526613163807108170062053440751665152000000000, 1405006117752879898543142606244511569936384000000000, 60415263063373835637355132068513997507264512000000000, 2658271574788448768043625811014615890319638528000000000, 119622220865480194561963161495657715064383733760000000000, 5502622159812088949850305428800254892961651752960000000000, 258623241511168180642964355153611979969197632389120000000000, 12413915592536072670862289047373375038521486354677760000000000, 608281864034267560872252163321295376887552831379210240000000000, 30414093201713378043612608166064768844377641568960512000000000000, 1551118753287382280224243016469303211063259720016986112000000000000, 80658175170943878571660636856403766975289505440883277824000000000000, 4274883284060025564298013753389399649690343788366813724672000000000000, 230843697339241380472092742683027581083278564571807941132288000000000000, 12696403353658275925965100847566516959580321051449436762275840000000000000, 710998587804863451854045647463724949736497978881168458687447040000000000000, 40526919504877216755680601905432322134980384796226602145184481280000000000000, 2350561331282878571829474910515074683828862318181142924420699914240000000000000, 138683118545689835737939019720389406345902876772687432540821294940160000000000000, 8320987112741390144276341183223364380754172606361245952449277696409600000000000000, 507580213877224798800856812176625227226004528988036003099405939480985600000000000000, 31469973260387937525653122354950764088012280797258232192163168247821107200000000000000, 1982608315404440064116146708361898137544773690227268628106279599612729753600000000000000, 126886932185884164103433389335161480802865516174545192198801894375214704230400000000000000, 8247650592082470666723170306785496252186258551345437492922123134388955774976000000000000000, 544344939077443064003729240247842752644293064388798874532860126869671081148416000000000000000, 36471110918188685288249859096605464427167635314049524593701628500267962436943872000000000000000, 2480035542436830599600990418569171581047399201355367672371710738018221445712183296000000000000000, 171122452428141311372468338881272839092270544893520369393648040923257279754140647424000000000000000, 11978571669969891796072783721689098736458938142546425857555362864628009582789845319680000000000000000, 850478588567862317521167644239926010288584608120796235886430763388588680378079017697280000000000000000, 61234458376886086861524070385274672740778091784697328983823014963978384987221689274204160000000000000000, 4470115461512684340891257138125051110076800700282905015819080092370422104067183317016903680000000000000000, 330788544151938641225953028221253782145683251820934971170611926835411235700971565459250872320000000000000000, 24809140811395398091946477116594033660926243886570122837795894512655842677572867409443815424000000000000000000, 1885494701666050254987932260861146558230394535379329335672487982961844043495537923117729972224000000000000000000, 145183092028285869634070784086308284983740379224208358846781574688061991349156420080065207861248000000000000000000, 11324281178206297831457521158732046228731749579488251990048962825668835325234200766245086213177344000000000000000000, 894618213078297528685144171539831652069808216779571907213868063227837990693501860533361810841010176000000000000000000, 71569457046263802294811533723186532165584657342365752577109445058227039255480148842668944867280814080000000000000000000, 5797126020747367985879734231578109105412357244731625958745865049716390179693892056256184534249745940480000000000000000000, 475364333701284174842138206989404946643813294067993328617160934076743994734899148613007131808479167119360000000000000000000, 39455239697206586511897471180120610571436503407643446275224357528369751562996629334879591940103770870906880000000000000000000, 3314240134565353266999387579130131288000666286242049487118846032383059131291716864129885722968716753156177920000000000000000000, 281710411438055027694947944226061159480056634330574206405101912752560026159795933451040286452340924018275123200000000000000000000, 24227095383672732381765523203441259715284870552429381750838764496720162249742450276789464634901319465571660595200000000000000000000, 2107757298379527717213600518699389595229783738061356212322972511214654115727593174080683423236414793504734471782400000000000000000000, 185482642257398439114796845645546284380220968949399346684421580986889562184028199319100141244804501828416633516851200000000000000000000, 16507955160908461081216919262453619309839666236496541854913520707833171034378509739399912570787600662729080382999756800000000000000000000, 1485715964481761497309522733620825737885569961284688766942216863704985393094065876545992131370884059645617234469978112000000000000000000000, 135200152767840296255166568759495142147586866476906677791741734597153670771559994765685283954750449427751168336768008192000000000000000000000, 12438414054641307255475324325873553077577991715875414356840239582938137710983519518443046123837041347353107486982656753664000000000000000000000, 1156772507081641574759205162306240436214753229576413535186142281213246807121467315215203289516844845303838996289387078090752000000000000000000000, 108736615665674308027365285256786601004186803580182872307497374434045199869417927630229109214583415458560865651202385340530688000000000000000000000, 10329978488239059262599702099394727095397746340117372869212250571234293987594703124871765375385424468563282236864226607350415360000000000000000000000, 991677934870949689209571401541893801158183648651267795444376054838492222809091499987689476037000748982075094738965754305639874560000000000000000000000, 96192759682482119853328425949563698712343813919172976158104477319333745612481875498805879175589072651261284189679678167647067832320000000000000000000000, 9426890448883247745626185743057242473809693764078951663494238777294707070023223798882976159207729119823605850588608460429412647567360000000000000000000000, 933262154439441526816992388562667004907159682643816214685929638952175999932299156089414639761565182862536979208272237582511852109168640000000000000000000000, 93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000
Wenn Sie die Werte dennoch selbst berechnen möchten, können Sie Memoization verwenden :
var f = [];
function factorial (n) {
if (n == 0 || n == 1)
return 1;
if (f[n] > 0)
return f[n];
return f[n] = factorial(n-1) * n;
}
Ich dachte, es wäre nützlich, ein funktionierendes Beispiel für eine faule iterative Fakultätsfunktion hinzuzufügen , die große Zahlen verwendet , um ein genaues Ergebnis mit Memoisierung und Cache als Vergleich zu erhalten
var f = [new BigNumber("1"), new BigNumber("1")];
var i = 2;
function factorial(n)
{
if (typeof f[n] != 'undefined')
return f[n];
var result = f[i-1];
for (; i <= n; i++)
f[i] = result = result.multiply(i.toString());
return result;
}
var cache = 100;
//due to memoization following line will cache first 100 elements
factorial(cache);
Ich gehe davon aus, dass Sie eine Art Verschluss verwenden würden , um die Sichtbarkeit von Variablennamen einzuschränken.
function factorial (n) { for (var i = f.length; i <= n; i++) f.push(f[i - 1].multiply(i.toString())); return f[n]; }
auch meine Antwort zu sehen , bei der die neuere integrierte Version BigInt
anstelle einer Bibliothek eines Drittanbieters verwendet wird.
Sie sollten eine Schleife verwenden.
Hier sind zwei Versionen, die durch 10.000-malige Berechnung der Fakultät 100 verglichen werden.
Rekursiv
function rFact(num)
{
if (num === 0)
{ return 1; }
else
{ return num * rFact( num - 1 ); }
}
Iterativ
function sFact(num)
{
var rval=1;
for (var i = 2; i <= num; i++)
rval = rval * i;
return rval;
}
Live unter: http://jsfiddle.net/xMpTv/
Meine Ergebnisse zeigen:
- Rekursiv ~ 150 Millisekunden
- Iterativ ~ 5 Millisekunden ..
rval = rval * i;
könnten Sie schreibenrval *= i;
Ich denke immer noch, dass Margus 'Antwort die beste ist. Wenn Sie jedoch auch die Fakultäten von Zahlen im Bereich von 0 bis 1 (dh die Gammafunktion) berechnen möchten, können Sie diesen Ansatz nicht verwenden, da die Nachschlagetabelle unendliche Werte enthalten muss.
Sie können jedoch die Werte der Fakultäten approximieren, und dies ist ziemlich schnell, schneller als sich selbst rekursiv aufzurufen oder zumindest zu schleifen (insbesondere, wenn die Werte größer werden).
Eine gute Näherungsmethode ist die von Lanczos
Hier ist eine Implementierung in JavaScript (portiert von einem Taschenrechner, den ich vor Monaten geschrieben habe):
function factorial(op) {
// Lanczos Approximation of the Gamma Function
// As described in Numerical Recipes in C (2nd ed. Cambridge University Press, 1992)
var z = op + 1;
var p = [1.000000000190015, 76.18009172947146, -86.50532032941677, 24.01409824083091, -1.231739572450155, 1.208650973866179E-3, -5.395239384953E-6];
var d1 = Math.sqrt(2 * Math.PI) / z;
var d2 = p[0];
for (var i = 1; i <= 6; ++i)
d2 += p[i] / (z + i);
var d3 = Math.pow((z + 5.5), (z + 0.5));
var d4 = Math.exp(-(z + 5.5));
d = d1 * d2 * d3 * d4;
return d;
}
Sie können jetzt coole Sachen wie factorial(0.41)
usw. machen, aber die Genauigkeit kann ein wenig abweichen, schließlich ist es eine Annäherung an das Ergebnis.
var d3d4 = Math.exp((z + 0.5) * Math.log(z + 5.5) - z - 5.5); return d1 * d2 * d3d4;
. Auf diese Weise können Sie Fakultäten bis zu 169 berechnen! statt derzeit nur 140!. Dies ist ziemlich nahe an der maximal darstellbaren Fakultät unter Verwendung des Number
Datentyps, der 170! Ist.
Die Nachschlagetabelle ist der naheliegende Weg, wenn Sie mit natürlichen Zahlen arbeiten. Um eine Fakultät in Echtzeit zu berechnen, können Sie sie mit einem Cache beschleunigen und die zuvor berechneten Zahlen speichern. Etwas wie:
factorial = (function() {
var cache = {},
fn = function(n) {
if (n === 0) {
return 1;
} else if (cache[n]) {
return cache[n];
}
return cache[n] = n * fn(n -1);
};
return fn;
})();
Sie können einige Werte vorberechnen, um sie noch schneller zu machen.
Hier ist meine Lösung:
function fac(n){
return(n<2)?1:fac(n-1)*n;
}
Es ist der einfachste Weg (weniger Zeichen / Zeilen), den ich gefunden habe, nur eine Funktion mit einer Codezeile.
Bearbeiten:
Wenn Sie wirklich einige Zeichen speichern möchten, können Sie eine Pfeilfunktion (21 Byte) verwenden :
f=n=>(n<2)?1:f(n-1)*n
f=n=>n?f(n-1)*n:1
...
Nur eine Zeile mit ES6
const factorial = n => !(n > 1) ? 1 : factorial(n - 1) * n;
factorial = n => n <= 1 ? 1 : factorial(n - 1) * n
kurze und einfache rekursive Funktion (Sie könnten dies auch mit einer Schleife tun, aber ich denke nicht, dass dies einen Unterschied in der Leistung bewirken würde):
function factorial (n){
if (n==0 || n==1){
return 1;
}
return factorial(n-1)*n;
}
Für ein sehr großes n könnten Sie die Stirlings-Näherung verwenden - aber das gibt Ihnen nur einen ungefähren Wert.
EDIT: Ein Kommentar, warum ich dafür eine Abwertung bekomme, wäre schön gewesen ...
EDIT2: Dies wäre die Soulution mit einer Schleife (was die bessere Wahl wäre):
function factorial (n){
j = 1;
for(i=1;i<=n;i++){
j = j*i;
}
return j;
}
Ich denke , die beste Lösung , um die im Cache gespeicherten Werte zu verwenden wäre, als Margus und die Verwendung erwähnte Stirlings Näherung für größere Werte (vorausgesetzt man muss wirklich schnell und muß nicht sein , dass genau auf so großen Zahlen).
Siehe, der Memoizer, der jede einzelne Argumentfunktion übernimmt und sie auswendig lernt. Es stellt sich heraus, dass es geringfügig schneller ist als die Lösung von @ xPheRe , einschließlich der Begrenzung der Größe des Caches und der damit verbundenen Überprüfung, da ich Kurzschlüsse usw. verwende.
function memoize(func, max) {
max = max || 5000;
return (function() {
var cache = {};
var remaining = max;
function fn(n) {
return (cache[n] || (remaining-- >0 ? (cache[n]=func(n)) : func(n)));
}
return fn;
}());
}
function fact(n) {
return n<2 ? 1: n*fact(n-1);
}
// construct memoized version
var memfact = memoize(fact,170);
// xPheRe's solution
var factorial = (function() {
var cache = {},
fn = function(n) {
if (n === 0) {
return 1;
} else if (cache[n]) {
return cache[n];
}
return cache[n] = n * fn(n -1);
};
return fn;
}());
Ungefähr 25x schneller auf meinem Computer in Chrome als in der rekursiven Version und 10% schneller als bei xPheRe.
Ich bin auf diesen Beitrag gestoßen. Inspiriert von allen Beiträgen hier habe ich meine eigene Version entwickelt, die zwei Funktionen enthält, die ich zuvor noch nicht besprochen habe: 1) Eine Überprüfung, um sicherzustellen, dass das Argument eine nicht negative Ganzzahl ist. 2) Eine Einheit aus dem Cache erstellen und die Funktion, es zu einem eigenständigen Codebit zu machen. Zum Spaß habe ich versucht, es so kompakt wie möglich zu machen. Einige mögen das elegant finden, andere mögen es für schrecklich dunkel halten. Wie auch immer, hier ist es:
var fact;
(fact = function(n){
if ((n = parseInt(n)) < 0 || isNaN(n)) throw "Must be non-negative number";
var cache = fact.cache, i = cache.length - 1;
while (i < n) cache.push(cache[i++] * i);
return cache[n];
}).cache = [1];
Sie können den Cache entweder vorab füllen oder ihn im Laufe der Anrufe füllen lassen. Aber das Anfangselement (für Tatsache (0) muss vorhanden sein, sonst wird es brechen.
Genießen :)
Ich denke, dass diese schleifenbasierte Version die schnellste Fakultätsfunktion sein könnte.
function factorial(n, r = 1) {
while (n > 0) r *= n--;
return r;
}
// Default parameters `r = 1`,
// was introduced in ES6
Und hier ist meine Argumentation:
for
Schleifen und while
Schleifen eine ähnliche Leistung haben, for
sieht eine Schleife ohne Initialisierungsausdruck und Endausdruck seltsam aus. wahrscheinlich besser zu schreiben for(; n > 0;)
alswhile(n > 0)
n
und r
verwendet werden, so in der Theorie weniger Parameter bedeuten weniger Zeit damit verbracht das Zuweisen von Speichern
Null ist. Ich habe Theorien gehört, dass Computer Binärzahlen (0 und 1) besser prüfen können als andere GanzzahlenMit ES6 ist das sehr einfach
const factorial = n => n ? (n * factorial(n-1)) : 1;
Sehen Sie ein Beispiel hier
Hier ist eine Lösung:
function factorial(number) {
total = 1
while (number > 0) {
total *= number
number = number - 1
}
return total
}
Mit ES6 können Sie es schnell und kurz erreichen:
const factorial = n => [...Array(n + 1).keys()].slice(1).reduce((acc, cur) => acc * cur, 1)
Der Code zur Berechnung der Fakultät hängt von Ihren Anforderungen ab.
In Bezug auf die Punkte 1 und 4 ist es oft nützlicher, eine Funktion zum direkten Auswerten des Protokolls der Fakultät zu haben, als eine Funktion zum Auswerten der Fakultät selbst.
Hier ist ein Blog-Beitrag , in dem diese Probleme behandelt werden. Hier ist ein C # -Code für die Berechnung der Protokollfaktor , der für die Portierung auf JavaScript trivial wäre. Abhängig von Ihren Antworten auf die obigen Fragen ist es möglicherweise nicht das Beste für Ihre Bedürfnisse.
Dies ist eine kompakte schleifenbasierte Version
function factorial( _n )
{
var _p = 1 ;
while( _n > 0 ) { _p *= _n-- ; }
return _p ;
}
Oder Sie überschreiben das Math-Objekt (rekursive Version):
Math.factorial = function( _x ) { return _x <= 1 ? 1 : _x * Math.factorial( --_x ) ; }
Oder verbinden Sie beide Ansätze ...
Unter Ausnutzung der Tatsache Number.MAX_VALUE < 171!
können wir einfach eine vollständige Nachschlagetabelle verwenden, die aus nur 171 kompakten Array-Elementen besteht, die weniger als 1,4 Kilobyte Speicher belegen.
Eine schnelle Suchfunktion mit Laufzeitkomplexität O (1) und minimalem Array-Zugriffsaufwand würde dann wie folgt aussehen:
// Lookup table for n! for 0 <= n <= 170:
const factorials = [1,1,2,6,24,120,720,5040,40320,362880,3628800,39916800,479001600,6227020800,87178291200,1307674368e3,20922789888e3,355687428096e3,6402373705728e3,121645100408832e3,243290200817664e4,5109094217170944e4,1.1240007277776077e21,2.585201673888498e22,6.204484017332394e23,1.5511210043330986e25,4.0329146112660565e26,1.0888869450418352e28,3.0488834461171387e29,8.841761993739702e30,2.6525285981219107e32,8.222838654177922e33,2.631308369336935e35,8.683317618811886e36,2.9523279903960416e38,1.0333147966386145e40,3.7199332678990125e41,1.3763753091226346e43,5.230226174666011e44,2.0397882081197444e46,8.159152832478977e47,3.345252661316381e49,1.40500611775288e51,6.041526306337383e52,2.658271574788449e54,1.1962222086548019e56,5.502622159812089e57,2.5862324151116818e59,1.2413915592536073e61,6.082818640342675e62,3.0414093201713376e64,1.5511187532873822e66,8.065817517094388e67,4.2748832840600255e69,2.308436973392414e71,1.2696403353658276e73,7.109985878048635e74,4.0526919504877214e76,2.3505613312828785e78,1.3868311854568984e80,8.32098711274139e81,5.075802138772248e83,3.146997326038794e85,1.98260831540444e87,1.2688693218588417e89,8.247650592082472e90,5.443449390774431e92,3.647111091818868e94,2.4800355424368305e96,1.711224524281413e98,1.1978571669969892e100,8.504785885678623e101,6.1234458376886085e103,4.4701154615126844e105,3.307885441519386e107,2.48091408113954e109,1.8854947016660504e111,1.4518309202828587e113,1.1324281178206297e115,8.946182130782976e116,7.156945704626381e118,5.797126020747368e120,4.753643337012842e122,3.945523969720659e124,3.314240134565353e126,2.81710411438055e128,2.4227095383672734e130,2.107757298379528e132,1.8548264225739844e134,1.650795516090846e136,1.4857159644817615e138,1.352001527678403e140,1.2438414054641308e142,1.1567725070816416e144,1.087366156656743e146,1.032997848823906e148,9.916779348709496e149,9.619275968248212e151,9.426890448883248e153,9.332621544394415e155,9.332621544394415e157,9.42594775983836e159,9.614466715035127e161,9.90290071648618e163,1.0299016745145628e166,1.081396758240291e168,1.1462805637347084e170,1.226520203196138e172,1.324641819451829e174,1.4438595832024937e176,1.588245541522743e178,1.7629525510902446e180,1.974506857221074e182,2.2311927486598138e184,2.5435597334721877e186,2.925093693493016e188,3.393108684451898e190,3.969937160808721e192,4.684525849754291e194,5.574585761207606e196,6.689502913449127e198,8.094298525273444e200,9.875044200833601e202,1.214630436702533e205,1.506141741511141e207,1.882677176888926e209,2.372173242880047e211,3.0126600184576594e213,3.856204823625804e215,4.974504222477287e217,6.466855489220474e219,8.47158069087882e221,1.1182486511960043e224,1.4872707060906857e226,1.9929427461615188e228,2.6904727073180504e230,3.659042881952549e232,5.012888748274992e234,6.917786472619489e236,9.615723196941089e238,1.3462012475717526e241,1.898143759076171e243,2.695364137888163e245,3.854370717180073e247,5.5502938327393044e249,8.047926057471992e251,1.1749972043909107e254,1.727245890454639e256,2.5563239178728654e258,3.80892263763057e260,5.713383956445855e262,8.62720977423324e264,1.3113358856834524e267,2.0063439050956823e269,3.0897696138473508e271,4.789142901463394e273,7.471062926282894e275,1.1729568794264145e278,1.853271869493735e280,2.9467022724950384e282,4.7147236359920616e284,7.590705053947219e286,1.2296942187394494e289,2.0044015765453026e291,3.287218585534296e293,5.423910666131589e295,9.003691705778438e297,1.503616514864999e300,2.5260757449731984e302,4.269068009004705e304,7.257415615307999e306];
// Lookup function:
function factorial(n) {
return factorials[n] || (n > 170 ? Infinity : NaN);
}
// Test cases:
console.log(factorial(NaN)); // NaN
console.log(factorial(-Infinity)); // NaN
console.log(factorial(-1)); // NaN
console.log(factorial(0)); // 1
console.log(factorial(170)); // 7.257415615307999e+306 < Number.MAX_VALUE
console.log(factorial(171)); // Infinity > Number.MAX_VALUE
console.log(factorial(Infinity)); // Infinity
Dies ist so präzise und schnell, wie es mit dem Number
Datentyp möglich ist. Das Berechnen der Nachschlagetabelle in Javascript verringert - wie einige andere Antworten vermuten lassen - die Genauigkeit, wenn n! > Number.MAX_SAFE_INTEGER
.
Durch das Komprimieren der Laufzeittabelle über gzip wird die Größe der Festplatte von etwa 3,6 auf 1,8 Kilobyte reduziert.
Einzeilige Antwort:
const factorial = (num, accumulator) => num <= 1 ? accumulator || 1 : factorial(--num, num * (accumulator || num + 1));
factorial(5); // 120
factorial(10); // 3628800
factorial(3); // 6
factorial(7); // 5040
// et cetera
BigInt
aus SicherheitsgründenDie Lösung verwendet
BigInt
eine ES 2018 + / 2019-Funktion.
Dies ist ein funktionierendes Beispiel BigInt
, da viele Antworten hier Number
fast sofort der sicheren Grenze von (MDN) entgehen . Es ist nicht das schnellste, aber es ist einfach und somit klarer für die Anpassung anderer Optimierungen (wie ein Cache der ersten 100 Zahlen).
function factorial(nat) {
let p = BigInt(1)
let i = BigInt(nat)
while (1 < i--) p *= i
return p
}
// 9.332621544394415e+157
Number(factorial(100))
// "933262154439441526816992388562667004907159682643816214685929638952175999
// 932299156089414639761565182862536979208272237582511852109168640000000000
// 00000000000000"
String(factorial(100))
// 9332621544394415268169923885626670049071596826438162146859296389521759999
// 3229915608941463976156518286253697920827223758251185210916864000000000000
// 000000000000n
factorial(100)
n
am Ende eines numerischen Literals wie 1303n
zeigt an, dass es sich um einen BigInt
Typ handelt.BigInt
mit , Number
wenn Sie sie ausdrücklich zwingen, und dass damit ein Verlust an Genauigkeit führen könnte.Kann mit ES6-Funktionen Code in EINE Zeile und ohne Rekursion schreiben :
var factorial=(n)=>Array.from({length: n},(v, k) => k+1).reduce((a, b) => a*b, 1)
Der Vollständigkeit halber ist hier eine rekursive Version, die eine Tail-Call-Optimierung ermöglichen würde. Ich bin mir nicht sicher, ob Tail-Call-Optimierungen in JavaScript durchgeführt werden.
function rFact(n, acc)
{
if (n == 0 || n == 1) return acc;
else return rFact(n-1, acc*n);
}
Um es zu nennen:
rFact(x, 1);
Dies ist eine iterative Lösung, die weniger Stapelspeicherplatz benötigt und zuvor berechnete Werte auf selbstmerkende Weise speichert:
Math.factorial = function(n){
if(this.factorials[n]){ // memoized
return this.factorials[n];
}
var total=1;
for(var i=n; i>0; i--){
total*=i;
}
this.factorials[n] = total; // save
return total;
};
Math.factorials={}; // store
Beachten Sie auch, dass ich dies dem Math-Objekt hinzufüge, das ein Objektliteral ist, sodass es keinen Prototyp gibt. Binden Sie diese einfach direkt an die Funktion.
Math.factorial(100); Math.factorial(500);
berechnet beispielsweise die 1..100-Multiplikation zweimal.
Ich glaube, das Folgende ist der nachhaltigste und effizienteste Code aus den obigen Kommentaren. Sie können dies in Ihrer globalen Anwendungsarchitektur verwenden ... und sich keine Sorgen machen, es in mehrere Namespaces zu schreiben (da es sich um eine Aufgabe handelt, die wahrscheinlich nicht viel erweitert werden muss). Ich habe 2 Methodennamen (je nach Präferenz) eingefügt, aber beide können verwendet werden, da sie nur Referenzen sind.
Math.factorial = Math.fact = function(n) {
if (isNaN(n)||n<0) return undefined;
var f = 1; while (n > 1) {
f *= n--;
} return f;
};
n * (n-1) * (n-2) * ... * 1
statt umgekehrt beginnen, verlieren Sie bis zu 4 Stellen Genauigkeit für n >> 20.
// if you don't want to update the Math object, use `var factorial = ...`
Math.factorial = (function() {
var f = function(n) {
if (n < 1) {return 1;} // no real error checking, could add type-check
return (f[n] > 0) ? f[n] : f[n] = n * f(n -1);
}
for (i = 0; i < 101; i++) {f(i);} // precalculate some values
return f;
}());
factorial(6); // 720, initially cached
factorial[6]; // 720, same thing, slightly faster access,
// but fails above current cache limit of 100
factorial(100); // 9.33262154439441e+157, called, but pulled from cache
factorial(142); // 2.6953641378881614e+245, called
factorial[141]; // 1.89814375907617e+243, now cached
Dadurch werden die ersten 100 Werte im laufenden Betrieb zwischengespeichert, und es wird keine externe Variable in den Bereich für den Cache eingefügt. Dabei werden die Werte als Eigenschaften des Funktionsobjekts selbst gespeichert. Wenn Sie also wissen, dass factorial(n)
sie bereits berechnet wurden, können Sie dies bezeichnen Sie es einfach als factorial[n]
, was etwas effizienter ist. Das Ausführen dieser ersten 100 Werte dauert in modernen Browsern weniger als eine Millisekunde.
21! > Number.MAX_SAFE_INTEGER
, dass es daher nicht sicher als 64-Bit-Float dargestellt werden kann.
Hier ist eine Implementierung, die sowohl positive als auch negative Fakultäten berechnet. Es ist schnell und einfach.
var factorial = function(n) {
return n > 1
? n * factorial(n - 1)
: n < 0
? n * factorial(n + 1)
: 1;
}
Hier ist eine, die ich selbst gemacht habe. Verwenden Sie keine Zahlen über 170 oder unter 2.
function factorial(x){
if((!(isNaN(Number(x)))) && (Number(x)<=170) && (Number(x)>=2)){
x=Number(x);for(i=x-(1);i>=1;--i){
x*=i;
}
}return x;
}
i
und führt viel zu viele Number
Konvertierungen durch und gibt falsche Ergebnisse für 0! (Wie Sie sagten, aber warum?).
Hier ist mein Code
function factorial(num){
var result = num;
for(i=num;i>=2;i--){
result = result * (i-1);
}
return result;
}
factorial(0)
. Wenn Sie Ihre Multiplikation mit n * (n-1) * (n-2) * ... * 1 anstatt umgekehrt beginnen, verlieren Sie bis zu 4 Stellen Genauigkeit für n >> 20. @prime: 170! > Number.MAX_VALUE
und ist am besten vertreten mit Infinity
.
Die zwischengespeicherte Schleife sollte am schnellsten sein (zumindest bei mehrmaligem Aufruf).
var factorial = (function() {
var x =[];
return function (num) {
if (x[num] >0) return x[num];
var rval=1;
for (var i = 2; i <= num; i++) {
rval = rval * i;
x[i] = rval;
}
return rval;
}
})();
function isNumeric(n) {
return !isNaN(parseFloat(n)) && isFinite(n)
}
Wird von http://javascript.info/tutorial/number-math bereitgestellt, um auf einfache Weise zu bewerten, ob ein Objekt eine geeignete Ganzzahl für die Berechnung ist.
var factorials=[[1,2,6],3];
Ein einfacher Satz von gespeicherten Fakultäten, die redundante Berechnungen erfordern, kann mit "mit 1 multiplizieren" verarbeitet werden oder ist eine Ziffer, die eine einfache Gleichung ist, die es nicht wert ist, live verarbeitet zu werden.
var factorial = (function(memo,n) {
this.memomize = (function(n) {
var ni=n-1;
if(factorials[1]<n) {
factorials[0][ni]=0;
for(var factorial_index=factorials[1]-1;factorials[1]<n;factorial_index++) {
factorials[0][factorials[1]]=factorials[0][factorial_index]*(factorials[1]+1);
factorials[1]++;
}
}
});
this.factorialize = (function(n) {
return (n<3)?n:(factorialize(n-1)*n);
});
if(isNumeric(n)) {
if(memo===true) {
this.memomize(n);
return factorials[0][n-1];
}
return this.factorialize(n);
}
return factorials;
});
Nachdem ich die Eingaben anderer Mitglieder überprüft hatte (mit Ausnahme der Protokollempfehlungen, obwohl ich diese möglicherweise später implementieren werde), habe ich ein Skript zusammengestellt, das ziemlich einfach ist. Ich begann mit einem einfachen ungebildeten JavaScript-OOP-Beispiel und baute eine kleine Klasse für den Umgang mit Fakultäten auf. Ich habe dann meine Version der oben vorgeschlagenen Memoization implementiert. Ich habe auch die Kurzfaktor-Faktorisierung implementiert, jedoch eine kleine Fehleranpassung vorgenommen. Ich habe "n <2" in "n <3" geändert. "n <2" würde immer noch n = 2 verarbeiten, was eine Verschwendung wäre, da Sie für 2 * 1 = 2 iterieren würden; Dies ist meiner Meinung nach eine Verschwendung. Ich habe es in "n <3" geändert; denn wenn n 1 oder 2 ist, gibt es einfach n zurück, wenn es 3 oder mehr ist, wird es normal ausgewertet. Da die Regeln gelten, habe ich meine Funktionen natürlich in absteigender Reihenfolge der angenommenen Ausführung angeordnet. Ich habe die Option bool (true | false) hinzugefügt, um einen schnellen Wechsel zwischen gespeicherter und normaler Ausführung zu ermöglichen (Sie wissen nur nie, wann Sie auf Ihrer Seite wechseln möchten, ohne den "Stil" ändern zu müssen) Die Variable für gespeicherte Fakultäten wird mit den 3 Startpositionen festgelegt, wobei 4 Zeichen verwendet werden und verschwenderische Berechnungen minimiert werden. Alles nach der dritten Iteration, mit der Sie zweistellige Mathematik plus verarbeiten. Ich denke, wenn Sie ein Stickler genug wären, würden Sie auf einer Fakultätstabelle (wie implementiert) laufen. Nehmen Sie 4 Zeichen und minimieren Sie verschwenderische Berechnungen. Alles nach der dritten Iteration, mit der Sie zweistellige Mathematik plus verarbeiten. Ich denke, wenn Sie ein Stickler genug wären, würden Sie auf einer Fakultätstabelle (wie implementiert) laufen. Nehmen Sie 4 Zeichen und minimieren Sie verschwenderische Berechnungen. Alles nach der dritten Iteration, mit der Sie zweistellige Mathematik plus verarbeiten. Ich denke, wenn Sie ein Stickler genug wären, würden Sie auf einer Fakultätstabelle (wie implementiert) laufen.
Was habe ich danach geplant? lokaler & | Sitzungsspeicher, um einen fallweisen Cache der erforderlichen Iterationen zu ermöglichen, wobei im Wesentlichen das oben erwähnte "Tabellen" -Problem behandelt wird. Dies würde auch massiv datenbank- und serverseitigen Speicherplatz sparen. Wenn Sie sich jedoch für localStorage entscheiden, würden Sie im Wesentlichen Speicherplatz auf dem Computer Ihres Benutzers beanspruchen, um einfach eine Liste von Zahlen zu speichern und den Bildschirm schneller aussehen zu lassen. Über einen langen Zeitraum mit einem immensen Bedarf wäre dies jedoch langsam. Ich denke, sessionStorage (Löschen nach Tab-Blättern) wäre eine viel bessere Route. Kombinieren Sie dies möglicherweise mit einem selbstausgleichenden Server / lokal abhängigen Cache? Benutzer A benötigt X Iterationen. Benutzer B benötigt Y-Iterationen. X + Y / 2 = Erforderlich lokal zwischengespeicherter Betrag. Dann erkennen Sie einfach die Benchmarks für Ladezeit und Ausführungszeit und spielen mit ihnen, bis sie sich an die Optimierung für die Site selbst anpassen. Vielen Dank!
Edit 3:
var f=[1,2,6];
var fc=3;
var factorial = (function(memo) {
this.memomize = (function(n) {
var ni=n-1;
if(fc<n) {
for(var fi=fc-1;fc<n;fi++) {
f[fc]=f[fi]*(fc+1);
fc++;
}
}
return f[ni];
});
this.factorialize = (function(n) {
return (n<3)?n:(factorialize(n-1)*n);
});
this.fractal = (function (functio) {
return function(n) {
if(isNumeric(n)) {
return functio(n);
}
return NaN;
}
});
if(memo===true) {
return this.fractal(memomize);
}
return this.fractal(factorialize);
});
Diese Bearbeitung implementiert einen weiteren Stack-Vorschlag und ermöglicht es mir, die Funktion als Fakultät (true) (5) zu bezeichnen, was eines meiner Ziele war. : 3 Ich habe auch einige unnötige Zuweisungen entfernt und einige nicht öffentliche Variablennamen kurzgeschrieben.
undefined
für 0!. ES6 ermöglicht das Ersetzen isNumeric
durch Number.isInteger
. Zeilen wie factorials[0][factorials[1]]=factorials[0][factorial_index]*(factorials[1]+1);
sind völlig unlesbar.
Hier ist eine, die neuere Javascript-Funktionen zum Füllen , Zuordnen , Reduzieren und Konstruieren (und zur Fettpfeilsyntax) verwendet:
Math.factorial = n => n === 0 ? 1 : Array(n).fill(null).map((e,i)=>i+1).reduce((p,c)=>p*c)
Bearbeiten: aktualisiert, um n === 0 zu behandeln
n === 0
. Math.factorial = n => Array.from({ length: n }).reduce((product, _, i) => product * (i + 1), 1)
function computeFactorialOfN(n) {
var output=1;
for(i=1; i<=n; i++){
output*=i;
} return output;
}
computeFactorialOfN(5);