Vous recherchez une implémentation très rapide de la fonction factorielle en JavaScript. Des suggestions?
Vous recherchez une implémentation très rapide de la fonction factorielle en JavaScript. Des suggestions?
Réponses:
Vous pouvez rechercher (1 ... 100)! sur Wolfram | Alpha pour pré-calculer la séquence factorielle.
Les 100 premiers nombres sont:
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
Si vous souhaitez toujours calculer les valeurs vous-même, vous pouvez utiliser la mémorisation :
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;
}
J'ai pensé qu'il serait utile d'ajouter un exemple fonctionnel de fonction factorielle itérative paresseuse qui utilise de grands nombres pour obtenir un résultat exact avec la mémorisation et le cache à titre de comparaison
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);
Je suppose que vous utiliseriez une sorte de fermeture pour limiter la visibilité des noms de variables.
function factorial (n) { for (var i = f.length; i <= n; i++) f.push(f[i - 1].multiply(i.toString())); return f[n]; }
voir également ma réponse qui utilise la bibliothèque intégrée plus récente BigInt
plutôt qu'une bibliothèque tierce.
Vous devez utiliser une boucle.
Voici deux versions comparées en calculant le factoriel de 100 pour 10 000 fois.
Récursif
function rFact(num)
{
if (num === 0)
{ return 1; }
else
{ return num * rFact( num - 1 ); }
}
Itératif
function sFact(num)
{
var rval=1;
for (var i = 2; i <= num; i++)
rval = rval * i;
return rval;
}
En direct sur: http://jsfiddle.net/xMpTv/
Mes résultats montrent:
- Récursif ~ 150 millisecondes
- Itératif ~ 5 millisecondes.
rval = rval * i;
vous pourriez écrirerval *= i;
Je pense toujours que la réponse de Margus est la meilleure. Cependant, si vous souhaitez également calculer les factorielles des nombres compris entre 0 et 1 (c'est-à-dire la fonction gamma), vous ne pouvez pas utiliser cette approche car la table de recherche devra contenir des valeurs infinies.
Cependant, vous pouvez approximer les valeurs des factorielles, et c'est assez rapide, plus rapide que de s'appeler récursivement ou de le boucler au moins (surtout lorsque les valeurs commencent à grossir).
Une bonne méthode d'approximation est celle de Lanczos
Voici une implémentation en JavaScript (portée à partir d'une calculatrice que j'ai écrite il y a des mois):
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;
}
Vous pouvez maintenant faire des trucs sympas comme factorial(0.41)
, etc., mais la précision peut être un peu mauvaise, après tout, c'est une approximation du résultat.
var d3d4 = Math.exp((z + 0.5) * Math.log(z + 5.5) - z - 5.5); return d1 * d2 * d3d4;
. Cela vous permet de calculer des factorielles jusqu'à 169! au lieu de seulement 140 actuellement !. C'est assez proche de la factorielle maximale représentable en utilisant le Number
type de données, qui est 170 !.
La table de recherche est la solution la plus évidente si vous travaillez avec des nombres naturels. Pour calculer n'importe quel factoriel en temps réel, vous pouvez l'accélérer avec un cache, en enregistrant les nombres que vous avez calculés auparavant. Quelque chose comme:
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;
})();
Vous pouvez précalculer certaines valeurs afin de l'accélérer encore plus.
Voici ma solution:
function fac(n){
return(n<2)?1:fac(n-1)*n;
}
C'est le moyen le plus simple (moins de caractères / lignes) que j'ai trouvé, seulement une fonction avec une ligne de code.
Edit:
Si vous voulez vraiment enregistrer des caractères, vous pouvez utiliser une fonction de flèche (21 octets) :
f=n=>(n<2)?1:f(n-1)*n
f=n=>n?f(n-1)*n:1
...
Juste une ligne avec ES6
const factorial = n => !(n > 1) ? 1 : factorial(n - 1) * n;
factorial = n => n <= 1 ? 1 : factorial(n - 1) * n
fonction récursive courte et facile (vous pouvez aussi le faire avec une boucle, mais je ne pense pas que cela ferait une différence dans les performances):
function factorial (n){
if (n==0 || n==1){
return 1;
}
return factorial(n-1)*n;
}
pour un n très grand, vous pouvez utiliser l' approximation de Stirlings - mais cela ne vous donnera qu'une valeur approximative.
EDIT: un commentaire sur les raisons pour lesquelles je reçois un vote négatif pour cela aurait été bien ...
EDIT2: ce serait la soulution utilisant une boucle (ce qui serait le meilleur choix):
function factorial (n){
j = 1;
for(i=1;i<=n;i++){
j = j*i;
}
return j;
}
Je pense que la meilleure solution serait d'utiliser les valeurs mises en cache, comme Margus l'a mentionné et d'utiliser l' approximation de Stirlings pour des valeurs plus grandes (en supposant que vous devez être vraiment rapide et que vous n'avez pas à être aussi exact sur de si grands nombres).
Voici le mémoizer, qui prend n'importe quelle fonction à argument unique et la mémorise. Se révèle être légèrement plus rapide que la solution de @ xPheRe , y compris la limite de la taille du cache et la vérification associée, car j'utilise un court-circuit et ainsi de suite.
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;
}());
Environ 25 fois plus rapide sur ma machine dans Chrome que la version récursive et 10% plus rapide que celle de xPheRe.
Je pense que cette version basée sur la boucle pourrait être la fonction factorielle la plus rapide.
function factorial(n, r = 1) {
while (n > 0) r *= n--;
return r;
}
// Default parameters `r = 1`,
// was introduced in ES6
Et voici mon raisonnement:
for
boucles et les while
boucles ont des performances similaires, une for
boucle sans expression d'initialisation et expression finale semble étrange; probablement mieux d'écrire for(; n > 0;)
commewhile(n > 0)
n
et r
sont utilisés, donc en théorie moins de paramètres signifie moins de temps passé à allouer de la mémoiren
est zéro - j'ai entendu des théories selon lesquelles les ordinateurs sont meilleurs pour vérifier les nombres binaires (0 et 1) qu'ils ne le sont pour vérifier d'autres entiersJe suis tombé sur ce post. Inspiré par toutes les contributions ici, j'ai proposé ma propre version, qui a deux fonctionnalités que je n'ai jamais vues auparavant: 1) Une vérification pour s'assurer que l'argument est un entier non négatif 2) Faire une unité à partir du cache et la fonction pour en faire un bit de code autonome. Pour le plaisir, j'ai essayé de le rendre aussi compact que possible. Certains peuvent trouver cela élégant, d'autres peuvent le trouver terriblement obscur. Bref, le voici:
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];
Vous pouvez soit pré-remplir le cache, soit l'autoriser à se remplir au fur et à mesure des appels. Mais l'élément initial (pour fact (0) doit être présent ou il se cassera.
Prendre plaisir :)
C'est très simple d'utiliser ES6
const factorial = n => n ? (n * factorial(n-1)) : 1;
Voir un exemple ici
Voici une solution:
function factorial(number) {
total = 1
while (number > 0) {
total *= number
number = number - 1
}
return total
}
En utilisant ES6, vous pouvez y parvenir à la fois rapidement et rapidement:
const factorial = n => [...Array(n + 1).keys()].slice(1).reduce((acc, cur) => acc * cur, 1)
Le code pour calculer factoriel dépend de vos besoins.
Concernant les points 1 et 4, il est souvent plus utile d'avoir une fonction pour évaluer le log directement de la factorielle plutôt que d'avoir une fonction pour évaluer la factorielle elle-même.
Voici un article de blog qui traite de ces problèmes. Voici un code C # pour calculer la factorielle du journal qui serait simple à porter en JavaScript. Mais ce n'est peut-être pas le meilleur pour vos besoins en fonction de vos réponses aux questions ci-dessus.
Ceci est une version compacte basée sur une boucle
function factorial( _n )
{
var _p = 1 ;
while( _n > 0 ) { _p *= _n-- ; }
return _p ;
}
Ou vous pouvez remplacer l'objet Math (version récursive):
Math.factorial = function( _x ) { return _x <= 1 ? 1 : _x * Math.factorial( --_x ) ; }
Ou rejoignez les deux approches ...
En exploitant le fait Number.MAX_VALUE < 171!
, nous pouvons simplement utiliser une table de recherche complète composée de seulement 171 éléments de tableau compact occupant moins de 1,4 kilo-octets de mémoire.
Une fonction de recherche rapide avec une complexité d'exécution O (1) et une surcharge minimale d'accès au tableau ressemblerait alors à ceci:
// 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
C'est aussi précis et aussi rapide que possible en utilisant le Number
type de données. Le calcul de la table de recherche en Javascript - comme le suggèrent d'autres réponses - réduira la précision quand n! > Number.MAX_SAFE_INTEGER
.
La compression de la table d'exécution via gzip réduit sa taille sur le disque d'environ 3,6 à 1,8 kilo-octets.
Réponse en une ligne:
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
pour la sécuritéLa solution utilise
BigInt
, une fonctionnalité ES 2018 + / 2019.
Cet exemple fonctionne BigInt
, car de nombreuses réponses ici échappent toutes Number
presque immédiatement à la limite de sécurité de (MDN). Ce n'est pas le plus rapide mais c'est simple et donc plus clair pour adapter d'autres optimisations (comme un cache des 100 premiers nombres).
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
à la fin d'un littéral numérique comme 1303n
indique qu'il s'agit d'un BigInt
type.BigInt
à Number
moins que vous ne les contraigniez explicitement, et cela pourrait entraîner une perte de précision.En utilisant les fonctionnalités ES6, peut écrire du code sur UNE seule ligne et sans récursivité :
var factorial=(n)=>Array.from({length: n},(v, k) => k+1).reduce((a, b) => a*b, 1)
Juste pour être complet, voici une version récursive qui permettrait une optimisation des appels de queue. Je ne suis pas sûr que les optimisations des appels de fin soient effectuées en JavaScript.
function rFact(n, acc)
{
if (n == 0 || n == 1) return acc;
else return rFact(n-1, acc*n);
}
Pour l'appeler:
rFact(x, 1);
Il s'agit d'une solution itérative qui utilise moins d'espace de pile et enregistre les valeurs précédemment calculées de manière auto-mémorisable:
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
Notez également que j'ajoute ceci à l'objet Math qui est un objet littéral donc il n'y a pas de prototype. Plutôt que de les lier directement à la fonction.
Math.factorial(100); Math.factorial(500);
calculera la multiplication 1..100 deux fois.
Je pense que ce qui suit est le morceau de code le plus durable et le plus efficace parmi les commentaires ci-dessus. Vous pouvez l'utiliser dans l'architecture js de votre application globale ... et, ne vous inquiétez pas de l'écrire dans plusieurs espaces de noms (car c'est une tâche qui n'a probablement pas besoin d'être augmentée). J'ai inclus 2 noms de méthodes (en fonction des préférences) mais les deux peuvent être utilisés car ce ne sont que des références.
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
au lieu de l'inverse, vous perdez jusqu'à 4 chiffres de précision pour 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
Cela met en cache les 100 premières valeurs à la volée et n'introduit pas de variable externe dans la portée du cache, en stockant les valeurs en tant que propriétés de l'objet fonction lui-même, ce qui signifie que si vous savez qu'il factorial(n)
a déjà été calculé, vous pouvez appelez-le simplement factorial[n]
, ce qui est légèrement plus efficace. L'exécution de ces 100 premières valeurs prendra moins d'une milliseconde dans les navigateurs modernes.
21! > Number.MAX_SAFE_INTEGER
, donc ne peut pas être représenté en toute sécurité comme un flottant 64 bits.
Voici une implémentation qui calcule les factorielles positives et négatives. C'est simple et rapide.
var factorial = function(n) {
return n > 1
? n * factorial(n - 1)
: n < 0
? n * factorial(n + 1)
: 1;
}
En voici un que j'ai créé moi-même, n'utilisez pas de nombres supérieurs à 170 ou inférieurs à 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
et effectue beaucoup trop de Number
conversions et donne des résultats incorrects pour 0! (comme vous l'avez dit, mais pourquoi?).
Voici mon code
function factorial(num){
var result = num;
for(i=num;i>=2;i--){
result = result * (i-1);
}
return result;
}
factorial(0)
. De plus, en commençant votre multiplication par n * (n-1) * (n-2) * ... * 1 au lieu de l'inverse, vous perdez jusqu'à 4 chiffres en précision pour n >> 20. @prime: 170! > Number.MAX_VALUE
et est mieux représenté avec Infinity
.
La boucle mise en cache doit être la plus rapide (au moins lorsqu'elle est appelée plusieurs fois)
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)
}
Fourni par http://javascript.info/tutorial/number-math comme moyen simple d'évaluer si un objet est un entier approprié pour le calcul.
var factorials=[[1,2,6],3];
Un ensemble simple de factorielles mémorisées qui nécessitent des calculs redondants, peuvent être traités avec "multiplier par 1", ou sont un chiffre qui est une équation simple qui ne vaut pas la peine d'être traitée en direct.
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;
});
Après avoir examiné les commentaires des autres membres (à l'exclusion des conseils du journal, bien que je puisse l'implémenter plus tard), je suis allé de l'avant et j'ai lancé un script assez simple. J'ai commencé avec un simple exemple de POO JavaScript sans instruction et j'ai construit une petite classe pour gérer les factorielles. J'ai ensuite implémenté ma version de la mémorisation suggérée ci-dessus. J'ai également implémenté la factorisation sténographique mais j'ai fait un petit ajustement d'erreur; J'ai changé le "n <2" en "n <3". "n <2" traiterait toujours n = 2, ce qui serait un gaspillage, car vous itéreriez pour un 2 * 1 = 2; c'est un gaspillage à mon avis. Je l'ai changé en "n <3"; car si n est 1 ou 2, il retournera simplement n, s'il est 3 ou plus, il s'évaluera normalement. Bien sûr, comme les règles s'appliquent, j'ai placé mes fonctions dans l'ordre décroissant d'exécution supposée. J'ai ajouté l'option bool (true | false) pour permettre une modification rapide entre l'exécution mémorisée et l'exécution normale (vous ne savez jamais quand vous voulez permuter sur votre page sans avoir besoin de changer le "style") Comme je l'ai dit avant le La variable factorielle mémorisée est définie avec les 3 positions de départ, prenant 4 caractères et minimisant les calculs inutiles. Tout après la troisième itération, vous gérez les mathématiques à deux chiffres plus. Je suppose que si vous étiez assez collant à ce sujet, vous courriez sur une table factorielle (telle qu'implémentée). prendre 4 caractères et minimiser les calculs inutiles. Tout après la troisième itération, vous gérez les mathématiques à deux chiffres plus. Je suppose que si vous étiez assez collant à ce sujet, vous courriez sur une table factorielle (telle qu'implémentée). prendre 4 caractères et minimiser les calculs inutiles. Tout après la troisième itération, vous gérez les mathématiques à deux chiffres plus. Je suppose que si vous étiez assez collant à ce sujet, vous courriez sur une table factorielle (telle qu'implémentée).
Qu'ai-je prévu après cela? stockage local et de session pour permettre un cache au cas par cas des itérations nécessaires, traitant essentiellement le problème de «table» mentionné ci-dessus. Cela permettrait également d'économiser massivement la base de données et l'espace côté serveur. Cependant, si vous optez pour localStorage, vous aspireriez essentiellement de l'espace sur l'ordinateur de vos utilisateurs simplement pour stocker une liste de numéros et rendre leur écran plus rapide, mais sur une longue période avec un immense besoin, cela serait lent. Je pense que sessionStorage (effacement après le départ de Tab) serait un bien meilleur itinéraire. Peut-être combiner cela avec un serveur auto-équilibré / un cache local dépendant? L'utilisateur A a besoin de X itérations. L'utilisateur B a besoin d'itérations Y. X + Y / 2 = Montant nécessaire mis en cache localement. Ensuite, il suffit de détecter et de jouer avec les benchmarks de temps de chargement et d'exécution en direct pour chaque utilisateur jusqu'à ce qu'il s'ajuste à l'optimisation du site lui-même. Merci!
Modifier 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);
});
Cette modification implémente une autre suggestion de Stack et me permet d'appeler la fonction factorielle (true) (5), ce qui était l'un de mes objectifs. : 3 J'ai également supprimé certaines affectations inutiles et raccourci certains noms de variables non publics.
undefined
pour 0 !. ES6 permet de remplacer isNumeric
par Number.isInteger
. Les lignes comme factorials[0][factorials[1]]=factorials[0][factorial_index]*(factorials[1]+1);
sont totalement illisibles.
En voici une qui utilise les nouvelles fonctions javascript fill , map , reduction et constructor (et la syntaxe de la grosse flèche):
Math.factorial = n => n === 0 ? 1 : Array(n).fill(null).map((e,i)=>i+1).reduce((p,c)=>p*c)
Edit: mis à jour pour gérer n === 0
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);