web-dev-qa-db-fra.com

Quelle est la fonction factorielle la plus rapide en JavaScript?

Vous recherchez une implémentation très rapide de factorial function en JavaScript. Tout suggère?

79
Ken

Vous pouvez rechercher (1 ... 100)! sur WolframAlpha pour pré-calculer la séquence factorielle.

Les 100 premiers numéros 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 voulez toujours calculer les valeurs vous-même, vous pouvez utiliser memoization :

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;
} ​

Edit: 21.08.2014

Solution 2

J'ai pensé qu'il serait utile d'ajouter un exemple de travail de lazy _ {itératiffonction factorielle qui utilise gros nombres pour obtenir exact résultat avec memoization et 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 variable.

Ref: BigNumberSandbox: JsFiddle

95
Margus

Vous devriez utiliser une boucle. 

Voici deux versions comparées en calculant la factorielle 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;
}

Live à: http://jsfiddle.net/xMpTv/

Mes résultats montrent:
- Récursif ~ 150 millisecondes
- Itératif ~ 5 millisecondes ..

82
Gabriele Petrioli

Je pense toujours que la réponse de Margus est la meilleure. Toutefois, si vous souhaitez également calculer les factorielles des nombres compris entre 0 et 1 (fonction gamma), vous ne pouvez pas utiliser cette approche car la table de correspondance devra contenir des valeurs infinies.

Cependant, vous pouvez approximer les valeurs des factorielles, et c'est assez rapide, plus rapide que de s'appeler de manière récursive ou de la 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 (basée sur 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 choses intéressantes comme factorial(0.41), etc. Cependant, la précision peut être un peu faible, après tout, il s’agit d’une approximation du résultat.

28
Waleed Amjad

La table de consultation est le moyen évident d'aller si vous travaillez avec des nombres naturels . Pour calculer une factorielle 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 pour accélérer encore davantage.

16
xPheRe

Voici ma solution:

function fac(n){
    return(n<2)?1:fac(n-1)*n;
}

C'est la manière la plus simple (moins de caractères/lignes) que j'ai trouvé, seulement une fonction avec une ligne de code.


Modifier:
Si vous voulez vraiment sauvegarder des caractères, vous pouvez utiliser un Fonction de flèche(21 octets):

f=n=>(n<2)?1:f(n-1)*n
11
Toni Almeida

fonction récursive courte et facile (vous pouvez le faire avec une boucle aussi, 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 très grand n, vous pouvez utiliser l'approximation stirlings - mais cela ne vous donnera qu'une valeur approximative.

EDIT: un commentaire sur la raison pour laquelle je reçois un vote négatif car cela aurait été agréable ...

EDIT2: ce serait la solution utilisant une boucle (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 en cache, comme Margus l’a mentionné, en utilisant l’approximation stirlings pour les valeurs plus grandes (supposons que vous soyez vraiment rapide} et que vous n’ayez pas à être that exact sur des nombres aussi grands).

8
oezi

Voici le mémoizer, qui prend n'importe quelle fonction à un seul argument et le mémoise. S'avère ê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 court-circuit, etc.

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 sous Chrome que la version récursive et 10% plus rapide que celle de xPheRe.

7
Phil H

Juste une ligne avec ES6 

const factorial =(n) =>!(n > 1) ? 1 : factorial(n - 1) * n;

const factorial =(n) =>!(n > 1) ? 1 : factorial(n - 1) * n;


function print(value) {
  document.querySelector('.result').innerHTML = value;
}
.result {
  margin-left: 10px;
}
<input onkeyup="print(factorial(this.value))" type="number"/>

<span class="result">......</span>

6
Abdennour TOUMI

Je suis tombé sur ce post. Inspiré par toutes les contributions ici, j'ai créé ma propre version, qui comporte deux caractéristiques que je n'ai jamais vues discutées auparavant: 1) Une vérification pour s'assurer que l'argument est un entier non négatif. unité hors du cache et la fonction pour en faire un morceau 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. Quoi qu'il en soit, la 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 le laisser être rempli au fur et à mesure des appels. Mais l'élément initial (pour le fait (0) doit être présent sinon il cassera. 

Prendre plaisir :)

5
Roland Bouman

Voici une solution:

function factorial(number) {
  total = 1
  while (number > 0) {
    total *= number
    number = number - 1
  }
  return total
}
4
Erika Smith

Le code pour calculer factoriel dépend de vos besoins. 

  1. Êtes-vous préoccupé par le débordement? 
  2. Quelle gamme d'entrées aurez-vous? 
  3. Est-il plus important pour vous de minimiser la taille ou le temps? 
  4. Qu'allez-vous faire avec la factorielle? 

En ce qui concerne les points 1 et 4, il est souvent plus utile d’avoir une fonction permettant d’évaluer directement le log de la factorielle plutôt que d’avoir une fonction permettant d’évaluer la factorielle elle-même.

Voici un blog post qui traite de ces problèmes. Voici un code C # pour le calcul du journal factoriel qu'il serait facile de porter en JavaScript. Mais cela peut ne pas être le mieux adapté à vos besoins, selon vos réponses aux questions ci-dessus.

3
John D. Cook

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 ...

3
Sandro Rosa
function isNumeric(n) {
    return !isNaN(parseFloat(n)) && isFinite(n)
}

Fourni par http://javascript.info/tutorial/number-math comme un moyen simple d'évaluer si un objet est un entier correct pour le calcul.

var factorials=[[1,2,6],3];

Un ensemble simple de factorielles mémorisées nécessitant des calculs redondants, peut être traité avec "multiplier par 1", ou est un chiffre qui est une équation simple ne méritant pas d'être traité 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 du conseil Log, bien que je puisse l’appliquer plus tard), j’ai poursuivi et jeté un script assez simple. J'ai commencé avec un simple exemple JavaScript OOP non éduqué 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 mis en œuvre la factorisation abrégée, mais j'ai effectué un léger ajustement d'erreur; J'ai changé le "n <2" en "n <3". "n <2" traiterait toujours n = 2, ce qui constituerait un gaspillage, car vous itéreriez pour un 2 * 1 = 2; c'est un gaspillage à mon avis. Je l'ai modifié pour "n <3"; parce que si n vaut 1 ou 2, il retournera simplement n, s'il est égal à 3 ou plus, il sera évalué normalement. Bien sûr, à mesure que les règles s’appliquent, j’ai placé mes fonctions dans l’ordre décroissant de l’exécution supposée. J'ai ajouté l'option bool (true | false) pour permettre une modification rapide entre l'exécution mémo'ed et normale (vous ne savez jamais quand vous voulez changer de page sans avoir besoin de changer le "style"). Avant que la variable factorielle mémorisée ne soit définie, elle est définie avec les 3 positions de départ, en prenant 4 caractères et en minimisant les calculs inutiles. Au-delà de la troisième itération, vous gérez des mathématiques à deux chiffres plus. J'imagine que si vous en étiez assez insistant, vous utiliseriez une table factorielle (telle qu'implémentée).

Qu’est-ce que j’ai prévu après cela? Local & | storage afin de permettre la mise en cache cas par cas des itérations nécessaires, en traitant essentiellement le problème de "table" évoqué ci-dessus. Cela permettrait également d'économiser massivement l'espace de la base de données et du serveur. Cependant, si vous utilisez localStorage, vous utiliserez essentiellement de l’espace sur l’ordinateur de vos utilisateurs pour simplement stocker une liste de numéros et rendre leur écran PLUS LOOK plus rapidement. Cependant, sur une longue période avec un besoin immense, cela serait lent. Je pense que sessionStorage (effacer après Tab feuilles) serait un meilleur chemin. Peut-être combiner cela avec un cache auto-équilibrant serveur/cache dépendant local? L'utilisateur A a besoin de X itérations . L'utilisateur B a besoin d'itérations . X + Y/2 = Quantité nécessaire mise en cache localement . détecter et bricoler avec le temps de chargement et les tests d'exécution-temps en direct pour chaque utilisateur jusqu'à ce qu'il s'adapte à l'optimisation pour le site lui-même . Merci!

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);
});

Cette modification implémente une autre suggestion de pile et me permet d'appeler la fonction factorielle (vraie) (5), ce qui était l'un de mes objectifs. : 3 J'ai également supprimé certaines attributions inutiles et abrégé certains noms de variables non publiques.

En utilisant ES6, vous pouvez le réaliser rapidement et rapidement:

const factorial=n=>[...Array(n+1).keys()].slice(1).reduce((acc,cur)=>acc*cur,1)
2
Amin Jafari

En exploitant le fait que Number.MAX_VALUE < 171!, nous pouvons simplement utiliser un table de consultation complète consistant en seulement 171 éléments de tableau compacts occupant moins de 1,4 kilo-octets de mémoire.

Une fonction de recherche rapide avec une complexité d'exécution O(1) et surcharge de l'accès minimal 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 avec le type de données Number. Le calcul de la table de consultation en Javascript - comme le suggèrent d’autres réponses - réduira la précision lorsque n! > Number.MAX_SAFE_INTEGER.

La compression du tableau d’exécution via gzip réduit sa taille sur disque de 3,6 à 1,8 kilo-octets environ.

2
le_m

Je crois que ce qui suit est le code le plus durable et le plus efficace des commentaires ci-dessus. Vous pouvez l'utiliser dans votre architecture globale d'applications Js ... sans vous soucier 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 (selon les préférences), mais les deux peuvent être utilisés car ils 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;
};
2
Joe Johnson

Voici mon code

function factorial(num){
    var result = num;
    for(i=num;i>=2;i--){
        result = result * (i-1);
    }
    return result;
}
2
cse031sust02
// 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

Ceci met en cache les 100 premières valeurs à la volée et n'introduit pas de variable externe dans la portée du cache, stockant les valeurs en tant que propriétés de l'objet fonction lui-même, ce qui signifie que si vous savez que factorial(n) a déjà été calculé, peut simplement s'y référer comme 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.

2
Scott Sauyet

D'après Wolfram MathWorld :

La factorielle n! est défini pour un entier positifn comme

n!=n(n-1)...2·1.

Par conséquent, vous pouvez utiliser la méthode suivante pour obtenir la factorielle d'un nombre:

const factorial = n => +!n || n * factorial(--n);

factorial(4) // 4! = 4 * 3 * 2 * 1 = 24
2
Grant Miller

Voici une implémentation qui calcule à la fois les factorielles positives et négatives ... C'est rapide et simple.

var factorial = function(n) {
  return n > 1
    ? n * factorial(n - 1)
    : n < 0
        ? n * factorial(n + 1)
        : 1;
}
2
Ilia Bykow

Juste pour être complet, voici une version récursive qui permettrait l’optimisation des appels Tail. Je ne suis pas sûr que les optimisations d'appel final 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);
2
Robert Jeppesen

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émo:

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 littéral d'objet, de sorte qu'il n'y a pas de prototype. Plutôt que de les lier directement à la fonction.

2
b-h-
    function factorial(num){    
        var num=Number(num);
        if (num < 0){
            return "this is not a positive number";
        }
        else{

        for (i=2 , f=1 ; i<=num;i++){

        f=f*i;

        }

    return f;
    }
    }
    // the function assumes that a number < 0 is null and factorial of any Word is considerate as factorial of 0 //

    console.log("-5! ="+factorial(-1));
    console.log("something ="+factorial("something"));
    console.log("15! ="+factorial(15));
    console.log("20! ="+factorial(20));
1
hakim

Cela retournera la factorielle de n

function f(n) {
    var e = n;
    if (e == 1 | e == 0) return 1;
    while (n--) {
        if (n < 1)
            break;
        e *= n;
    }
    return e
}
1
Ben Johnson mk2

Ce serait probablement très simple au début et peut-être que vous définiriez mieux ce code court en fonction de vos besoins:

<body>

    <button  onclick="fact()">Open the Prompt</button>
    <h2 id="output"></h2>

    <script>

    function fact(){ 
        var enter=Prompt("Enter You Factorial Number Bellow :","");
        var Num_enter=Number(enter);

        for (var i=1,FactNumber=1;i<=Num_enter;i++){

        FactNumber=FactNumber*i;
        }

        if(Num_enter){ 
           document.getElementById("output").textContent="the factorial of "+ Num_enter + " is: "+Num_enter+"!= "+ FactNumber;
        }


     }

   </script>


 </body>
1
hakim
var factorial = function() {
    var memo = [1];
    var facto = function (n) {
        var result = memo[n];
    if (typeof result !== 'number'){
        result = facto(n-1)*n;
    }
        return result;
    };
    return facto;
}();

Pour calculer la factorielle d'un nombre à l'aide de la mémorisation, appelez avec factorial(n).

1
broken_arrow

C’est la façon la plus simple que je connaisse de créer une fonction factorielle 

function factorial(num) {

    var result = 1;
    for(var i = 2; i<= num; i++) {
        result *= i;
    }
    return result;
}
1
Timmy
function computeFactorialOfN(n) {
  var output=1;
  for(i=1; i<=n; i++){
    output*=i;
  } return output;
}
computeFactorialOfN(5);
1
Odiljon Djamalov

En voici un que j'ai créé moi-même, n'utilisez pas de chiffres 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;
}
1
TheBestGuest

En voici une qui utilise les nouvelles fonctions javascript fill , map , reduction et constructor (et la syntaxe de la flèche épaisse):

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

1
Ashley Coolman

En utilisant les fonctions de l’ES6, vous pouvez écrire du code sur UNE ligne & sans récursion

var factorial=(n)=>Array.from({length:n},(v,k)=>k+1).reduce((a,b)=>a*b,1)
1
Abdennour TOUMI

Vous pouvez utiliser

function factorial(n) {
    return [...Array(n+1).keys()].slice(1).reduce( (a,b) => a * b, 1 );
}
1

Eh bien cette question a plus que suffisamment de réponses, mais juste pour poster une solution lisible, rapide et courte pour factorielle et factorielle inverse.

{
    const cache = [1, 1];
    let i = 2;

    function factorial(n) {
        if (!isFinite(n = parseInt(n)) || n < 0)
            throw new Error('argument for factorial has to be a positive finite integer but was ' + n);

        for (; i <= n; i++)
            cache[i] = cache[i - 1] * i;

        return cache[n];
    }

    function reverseFactorial(n) {
        if (!isFinite(n = parseFloat(n)) || n < 0)
            throw new Error('argument for reverseFactorial has to be a positive finite floatingpoint number but was ' + n);

        let f = 1;

        while (true)
            if (factorial(++f) >= n)
                return f - 1; // lower bound (f! which will fit in the given n, for upper bound just return f)

    }
}

reverseFactorial retournera un k qui est le plus grand k! qui correspond au n donné.

Les deux fonctions bénéficient du cache construit par factorial.

Si vous voulez le tester un peu:

for (let i = 0; i < 10; i++) {
    let random = Math.random() * 100;
    random = factorial(random) * Math.random() * random;

    const reverse = reverseFactorial(random);
    const resultOfReverse = factorial(reverse);

    function expo(x) {
        return x.toExponential(2);
    }

    console.log('%s fits %d! which is %s (upper bound %d! is %s)', expo(random), reverse, expo(resultOfReverse), reverse + 1, expo(factorial(reverse + 1)));
}
1
Feirell

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;
  }
})();
1
Сухой27
 used closure  for this with the helper (getFact) , I think this approach is neat hope this helps  


    factorial of n : using closures*/

    function getFact(num) {

        if (num > 1)
            return num * getFact(num - 1);
        else
            return 1;

    }


    function makeFact(fn) {
        return function(num) {
            return fn(num);
        }


    }

   makeFact(getFact)(5) //120
0
var factorial = (function() {
    var cache = [1];
    return function(value) {
        for (var index = cache.length; index <= value; index++) {
            cache[index] = index * cache[index - 1]
        }
        return cache[value];
    }
})();

Je trouve cela utile dans les mêmes cas:

function factorialDivision(n, d) {
    var value = 1;
    for (d++ < n) {
        value *= d;
    }
    return value;
}
0
Triqui

Facteur itératif avec BigInt pour la sécurité

La solution utilise BigInt , fonction ES 2018 +/2019.

Cet exemple de travail utilise BigInt, car beaucoup de réponses ici échappent presque immédiatement à la limite de sécurité de Number (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 chiffres).

function factorial(nat) {
   let p = BigInt(1)
   let i = BigInt(nat)

   while (1 < i--) p *= i

   return p
}

Exemple d'utilisation

// 9.332621544394415e+157
Number(factorial(100))

// "933262154439441526816992388562667004907159682643816214685929638952175999
//  932299156089414639761565182862536979208272237582511852109168640000000000
//  00000000000000"
String(factorial(100))

// 9332621544394415268169923885626670049071596826438162146859296389521759999
// 3229915608941463976156518286253697920827223758251185210916864000000000000
// 000000000000n
factorial(100)
  • La n à la fin d'un littéral numérique tel que 1303n indique qu'il s'agit d'un type BigInt.
  • Rappelez-vous que vous ne devez pas mélanger BigInt avec Number à moins de les contraindre explicitement, ce qui pourrait entraîner une perte de précision.
0
Meow

Fonction factorielle la plus rapide

Je pense que cette version en 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:

  • Les fonctions récursives, même avec la mémorisation, ont le surcoût d'un appel de fonction (poussant essentiellement des fonctions sur la pile) qui est moins performant que d'utiliser une boucle
  • Alors que les boucles for et les boucles while ont des performances similaires, une boucle for sans expression d'initialisation ni expression finale a l'air bizarre; Mieux vaut probablement écrire for(; n > 0;) comme while(n > 0)
  • Seuls deux paramètres n et r sont utilisés; ainsi, en théorie, moins de paramètres signifie moins de temps consacré à l'allocation de mémoire.
  • Utilise une boucle décrémentée qui vérifie si n est égal à 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 les autres entiers
0
tfmontague

Voici ma solution utilisant la fonction et la récursivité IIFy:

console.log((function factorial(n){return (n>1)?n*factorial(n-1):1;})(10))

C'est une solution optimale pour obtenir la sortie de factorial dans une seule ligne de code.

0
Mayank Tiwari

Vieille question mais je trouve cette approche assez lisible et directe

function factorialize(num) {
  var arr = [];
  var result;
  if ( num === 0 || num === 1 ) {
    return 1;
  } else {
    for (var i = num; i > 0; i--) {
      arr.Push(i);
      result = arr.reduce(function(previousVal, nextVal){
                return previousVal * nextVal;
              });
    }
    return result;
  }
}
0
pSkarl

Bien que toutes les solutions ci-dessus soient bonnes, mais elles semblent toutes trop longues pour moi, je me suis donc approprié la mienne.

function factorial(n) {              //"n" is the number used in the factorial

    var ans = 1,                     //define the base variables
        neg = false,
        n = Math.round(n);

    if (n<0 || !n) neg = true;       //check if the number is negative or if the number doesn't exist

    for (var i=1;i<=n;i++) ans *= i; //the actual repeating code, won't run if the number is less than or equal to 0

    return neg ? NaN : ans;          //return the answer if the original was positive

}

Le fonctionnement de la boucle for ne fera automatiquement rien pour les nombres inférieurs à 1. Donc, fondamentalement, "si (Le nombre) est inférieur ou égal à 0, vous renverrez alors 1.

Les lignes if (n<0 || !n) neg = true; et return neg ? NaN : ans; fonctionnent ensemble pour indiquer "Si le nombre est négatif, renvoyez NaN (pas un nombre)". Celles-ci vérifient également si le nombre existe même et renverront la NaN (pas un nombre) si le nombre n'existe pas.

Remarque

Au moins sur Chrome v50.0.2661.86 (64 bits), son nombre maximal est de 170. Ainsi, si vous exécutez cette fonction sur un nombre supérieur à 170 (171 par exemple), il renverra infinity.

0
Jaketr00

Réponse en 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

0
timgfx

Voici une approche qui n'a pas encore été fournie. Avec BigInt et la mémorisation, nous pouvons obtenir des résultats précis et ignorer les calculs pour les valeurs déjà calculées:

// using let and const, block scope can be used instead of IIFE for closure
{
  const lut = [1n, 1n];
  
  // returns factorial as BigInt instead of Number
  function factorial (n) {
    if (n >= lut.length) {
      for (let i = lut.length; i <= n; i++) {
        lut.Push(BigInt(i) * lut[i - 1]);
      }
    }

    return lut[n];
  }
}

console.log('starting');
// first time will require computation
console.log(factorial(10000).toString());
// second time will return result from cache
console.log(factorial(10000).toString());
div.as-console-wrapper { overflow-x: scroll; }
0
Patrick Roberts

Puisqu'une factorielle est simplement une multiplication dégénérative du nombre donné à 1, il serait en effet plus facile de passer en revue la multiplication:

Math.factorial = function(n) {

  if (n === 0||n === 1) {

    return 1;

  } else {

    for(var i = n; i > 0; --i) { //always make sure to decrement the value BEFORE it's tacked onto the original as a product
      n *= i;
    }

    return n;

  }

}
0
realkstrawn93
var factorial = function(numToBeFactored)
    {
        if (numToBeFactored == 0)
                return 1;
            var numLength = 0;
            var numBeingFactored = 1;
        /*goes through the loop numToBeFactored times and each time multiplies numBeingFactored by one less than the last loop*/
            for (numLength = 0; numLength < numToBeFactored; numLength++)
            {
                numBeingFactored *= (numToBeFactored - numLength);
            }
            return numBeingFactored;
    };
0
anonymous

Solution à une ligne pour les options itératives et récursives;

const rf = n => 1 === n ? 1 : rf( n - 1 ) * n;

const sf = n => {for (var i = n, c = 1; i > 1; i --) c *= i; return c;}
0
harry

Itératif: Math.factorial=n=>{for(var o=n;n>1;)o*=--n;return o};

Récursif: Math.factorial=n=>n>1?n--*Math.fac(n):1;

Précalculé: (_=>{let f=[],i=0;for(;i<171;i++)f[i]=(n=>{for(var o=n;n>1;)o*=--n;return o})(i);Math.factorial=n=>{n=Math.round(n);return n<171?f[n]:Infinity}})();

https://code.sololearn.com/Wj4rlA27C9fD . Ici, je pourrais poster plus de solutions.

0
NZ.