Procurando uma implementação realmente rápida de função fatorial em JavaScript. Algum sugere?
Procurando uma implementação realmente rápida de função fatorial em JavaScript. Algum sugere?
Respostas:
Você pode pesquisar por (1 ... 100)! no Wolfram | Alpha para pré-calcular a seqüência fatorial.
Os primeiros 100 números são:
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
Se você ainda deseja calcular os valores sozinho, pode usar a memoização :
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;
}
Achei que seria útil adicionar um exemplo funcional de função fatorial iterativa preguiçosa que usa números grandes para obter o resultado exato com memoização e cache como comparação
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);
Presumo que você usaria algum tipo de encerramento para limitar a visibilidade do nome da variável.
function factorial (n) { for (var i = f.length; i <= n; i++) f.push(f[i - 1].multiply(i.toString())); return f[n]; }
ver também minha resposta, que usa a BigInt
biblioteca integrada mais recente em vez de uma biblioteca de terceiros.
Você deve usar um loop.
Aqui estão duas versões comparadas calculando o fatorial de 100 para 10.000 vezes.
Recursiva
function rFact(num)
{
if (num === 0)
{ return 1; }
else
{ return num * rFact( num - 1 ); }
}
Iterativo
function sFact(num)
{
var rval=1;
for (var i = 2; i <= num; i++)
rval = rval * i;
return rval;
}
Ao vivo em: http://jsfiddle.net/xMpTv/
Meus resultados mostram:
- Recursivo ~ 150 milissegundos
- Iterativo ~ 5 milissegundos ..
rval = rval * i;
você poderia escreverrval *= i;
Ainda acho que a resposta de Margus é a melhor. No entanto, se você quiser calcular os fatoriais de números dentro do intervalo de 0 a 1 (ou seja, a função gama) também, você não pode usar essa abordagem porque a tabela de pesquisa terá que conter valores infinitos.
No entanto, você pode aproximar os valores dos fatoriais e é muito rápido, mais rápido do que chamar a si mesmo recursivamente ou pelo menos fazer um loop (especialmente quando os valores começam a ficar maiores).
Um bom método de aproximação é o de Lanczos
Aqui está uma implementação em JavaScript (transferida de uma calculadora que escrevi meses atrás):
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;
}
Agora você pode fazer coisas legais como factorial(0.41)
etc, porém a precisão pode estar um pouco errada, afinal, é uma aproximação do resultado.
var d3d4 = Math.exp((z + 0.5) * Math.log(z + 5.5) - z - 5.5); return d1 * d2 * d3d4;
. Isso permite que você calcule fatoriais de até 169! em vez de atualmente apenas 140 !. Isso é muito próximo do fatorial máximo representável usando o Number
tipo de dados, que é 170 !.
A tabela de pesquisa é o caminho óbvio, se você estiver trabalhando com números naturais. Para calcular qualquer fatorial em tempo real, você pode acelerá-lo com um cache, salvando os números que você calculou antes. Algo como:
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;
})();
Você pode pré-calcular alguns valores para acelerar ainda mais.
Aqui está minha solução:
function fac(n){
return(n<2)?1:fac(n-1)*n;
}
É a maneira mais simples (menos caracteres / linhas) que encontrei, apenas uma função com uma linha de código.
Edit:
Se você realmente deseja salvar alguns caracteres, pode usar uma função de seta (21 bytes) :
f=n=>(n<2)?1:f(n-1)*n
f=n=>n?f(n-1)*n:1
...
Apenas uma linha com ES6
const factorial = n => !(n > 1) ? 1 : factorial(n - 1) * n;
factorial = n => n <= 1 ? 1 : factorial(n - 1) * n
função recursiva curta e fácil (você também poderia fazer isso com um loop, mas não acho que isso faria qualquer diferença no desempenho):
function factorial (n){
if (n==0 || n==1){
return 1;
}
return factorial(n-1)*n;
}
para um n muito grande, você poderia usar a aproximação de Stirlings - mas isso só fornecerá um valor aproximado.
EDITAR: um comentário sobre por que estou recebendo uma votação negativa para isso teria sido bom ...
EDIT2: esta seria a solução usando um loop (que seria a melhor escolha):
function factorial (n){
j = 1;
for(i=1;i<=n;i++){
j = j*i;
}
return j;
}
Acho que a melhor solução seria usar os valores em cache, como Margus mencionou, e usar a aproximação de stirlings para valores maiores (assumindo que você precisa ser muito rápido e não precisa ser tão exato em números tão grandes).
Veja, o memoizer, que pega qualquer função de argumento único e a memoriza. Acontece ser um pouco mais rápido do que a solução de @ xPheRe , incluindo o limite do tamanho do cache e a verificação associada, porque eu uso curto-circuito e assim por diante.
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;
}());
Aproximadamente 25x mais rápido em minha máquina no Chrome do que a versão recursiva e 10% mais rápido do que o xPheRe.
Acho que esta versão baseada em loop pode ser a função fatorial mais rápida.
function factorial(n, r = 1) {
while (n > 0) r *= n--;
return r;
}
// Default parameters `r = 1`,
// was introduced in ES6
E aqui está o meu raciocínio:
for
loops e while
loops tenham desempenho semelhante, um for
loop sem uma expressão de inicialização e uma expressão final parece estranho; provavelmente melhor escrever for(; n > 0;)
comowhile(n > 0)
n
e r
são usados, então, em teoria, menos parâmetros significa menos tempo gasto na alocação de memórian
é zero - ouvi teorias de que os computadores são melhores na verificação de números binários (0 e 1) do que em outros inteirosMe deparei com este post. Inspirado por todas as contribuições aqui, eu vim com minha própria versão, que tem dois recursos que não tinha discutido antes: 1) Uma verificação para garantir que o argumento é um número inteiro não negativo 2) Fazer uma unidade fora do cache e a função para torná-lo um pedaço de código independente. Para me divertir, tentei torná-lo o mais compacto possível. Alguns podem achar isso elegante, outros podem pensar que é terrivelmente obscuro. Enfim, aqui está:
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];
Você pode pré-preencher o cache ou permitir que ele seja preenchido conforme as chamadas vão passando. Mas o elemento inicial (por fato (0) deve estar presente ou será quebrado.
Aproveitar :)
Aqui está uma solução:
function factorial(number) {
total = 1
while (number > 0) {
total *= number
number = number - 1
}
return total
}
Usando ES6, você pode alcançá-lo rápido e curto:
const factorial = n => [...Array(n + 1).keys()].slice(1).reduce((acc, cur) => acc * cur, 1)
O código para calcular o fatorial depende de seus requisitos.
Em relação aos pontos 1 e 4, muitas vezes é mais útil ter uma função para avaliar o log do fatorial diretamente do que ter uma função para avaliar o próprio fatorial.
Aqui está uma postagem de blog que discute esses problemas. Aqui está um código C # para calcular o fatorial de log que seria trivial portar para JavaScript. Mas pode não ser o melhor para suas necessidades, dependendo de suas respostas às perguntas acima.
Esta é uma versão baseada em loop compacto
function factorial( _n )
{
var _p = 1 ;
while( _n > 0 ) { _p *= _n-- ; }
return _p ;
}
Ou você pode substituir o objeto Math (versão recursiva):
Math.factorial = function( _x ) { return _x <= 1 ? 1 : _x * Math.factorial( --_x ) ; }
Ou junte as duas abordagens ...
Explorando o fato de que Number.MAX_VALUE < 171!
podemos simplesmente usar uma tabela de pesquisa completa consiste em apenas 171 elementos compactos de array, ocupando menos de 1,4 kilobytes de memória.
Uma função de pesquisa rápida com complexidade de tempo de execução O (1) e sobrecarga mínima de acesso ao array ficaria assim:
// 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
Isso é tão preciso e rápido quanto possível usando o Number
tipo de dados. Computando a tabela de pesquisa em Javascript - como algumas outras respostas sugerem - reduzirá a precisão quando n! > Number.MAX_SAFE_INTEGER
.
Compactar a tabela de tempo de execução via gzip reduz seu tamanho no disco de cerca de 3,6 para 1,8 kilobytes.
Resposta de uma linha:
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
para segurançaA solução usa
BigInt
, um recurso ES 2018 + / 2019.
Este é um exemplo de uso funcional BigInt
, porque muitas respostas aqui escapam Number
quase imediatamente do limite seguro de (MDN). Não é o mais rápido, mas é simples e, portanto, mais claro para adaptar outras otimizações (como um cache dos primeiros 100 números).
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
no final de um literal numérico como 1303n
indica que é umBigInt
tipo.BigInt
com a Number
menos que os coage explicitamente, e isso pode causar perda de precisão.Usando os recursos do ES6, pode escrever código em UMA linha e sem recursão :
var factorial=(n)=>Array.from({length: n},(v, k) => k+1).reduce((a, b) => a*b, 1)
Apenas para completar, aqui está uma versão recursiva que permitiria a otimização da chamada final. Não tenho certeza se as otimizações de chamada final são realizadas em JavaScript.
function rFact(n, acc)
{
if (n == 0 || n == 1) return acc;
else return rFact(n-1, acc*n);
}
Para chamá-lo:
rFact(x, 1);
Esta é uma solução iterativa que usa menos espaço na pilha e salva os valores calculados anteriormente de forma autolimitada:
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
Observe também que estou adicionando isso ao objeto Math, que é um objeto literal, portanto, não há protótipo. Em vez disso, apenas vinculando-os diretamente à função.
Math.factorial(100); Math.factorial(500);
irá calcular a multiplicação 1..100 duas vezes.
Eu acredito que o seguinte é o trecho de código mais sustentável e eficiente dos comentários acima. Você pode usar isso na arquitetura js de seu aplicativo global ... e não se preocupe em escrevê-lo em vários namespaces (já que é uma tarefa que provavelmente não precisa de muito aumento). Incluí 2 nomes de métodos (com base na preferência), mas ambos podem ser usados porque são apenas referências.
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
vez do contrário, você perde até 4 dígitos na precisão para 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
Isso faz o cache dos primeiros 100 valores em tempo real e não introduz uma variável externa no escopo do cache, armazenando os valores como propriedades do próprio objeto de função, o que significa que se você sabe factorial(n)
que já foi calculado, você pode basta referir-se a ele como factorial[n]
, que é um pouco mais eficiente. A execução desses primeiros 100 valores levará menos de um milissegundo em navegadores modernos.
21! > Number.MAX_SAFE_INTEGER
, portanto, não pode ser representado com segurança como um float de 64 bits.
Aqui está uma implementação que calcula fatoriais positivos e negativos. É rápido e simples.
var factorial = function(n) {
return n > 1
? n * factorial(n - 1)
: n < 0
? n * factorial(n + 1)
: 1;
}
Aqui está um que eu mesmo fiz, não use números acima de 170 ou abaixo de 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
e executa muitas Number
conversões e dá resultados incorretos para 0! (como você afirmou, mas por quê?).
Aqui está meu código
function factorial(num){
var result = num;
for(i=num;i>=2;i--){
result = result * (i-1);
}
return result;
}
factorial(0)
. Além disso, ao iniciar sua multiplicação com n * (n-1) * (n-2) * ... * 1 em vez do contrário, você perde até 4 dígitos na precisão para n >> 20. @prime: 170! > Number.MAX_VALUE
e é melhor representado com Infinity
.
function isNumeric(n) {
return !isNaN(parseFloat(n)) && isFinite(n)
}
Fornecido por http://javascript.info/tutorial/number-math como uma maneira simples de avaliar se um objeto é um número inteiro adequado para cálculo.
var factorials=[[1,2,6],3];
Um conjunto simples de fatoriais memorizados que requerem cálculos redundantes, podem ser processados com "multiplicação por 1", ou são um dígito que é uma equação simples que não vale a pena processar ao vivo.
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;
});
Depois de revisar a entrada de outros membros (excluindo o conselho do Log, embora eu possa implementá-lo mais tarde), fui em frente e criei um script que é bastante simples. Comecei com um exemplo simples de JavaScript OOP não educado e construí uma pequena classe para lidar com fatoriais. Em seguida, implementei minha versão da Memoização sugerida acima. Também implementei a Fatorialização abreviada, porém fiz um pequeno ajuste de erro; Mudei o "n <2" para "n <3". "n <2" ainda processaria n = 2, o que seria um desperdício, porque você iteraria para um 2 * 1 = 2; isso é um desperdício na minha opinião. Eu alterei para "n <3"; porque se n for 1 ou 2 ele simplesmente retornará n, se for 3 ou mais ele avaliará normalmente. Claro, como as regras se aplicam, coloquei minhas funções em ordem decrescente de execução presumida. Eu adicionei a opção bool (true | false) para permitir a alteração rápida entre a execução memorizada e normal (você nunca sabe quando quer trocar em sua página sem precisar mudar o "estilo") Como eu disse antes do A variável memoized factorials é definida com as 3 posições iniciais, pegando 4 caracteres e minimizando o desperdício de cálculos. Tudo após a terceira iteração, você está lidando com matemática de dois dígitos plus. Eu imagino que se você fosse um defensor o suficiente sobre isso, você executaria em uma tabela fatorial (conforme implementada). pegando 4 caracteres e minimizando cálculos inúteis. Tudo após a terceira iteração, você está lidando com matemática de dois dígitos plus. Eu imagino que se você fosse um defensor o suficiente sobre isso, você executaria em uma tabela fatorial (conforme implementada). pegando 4 caracteres e minimizando cálculos inúteis. Tudo após a terceira iteração, você está lidando com matemática de dois dígitos plus. Eu imagino que se você fosse um defensor o suficiente sobre isso, você executaria em uma tabela fatorial (conforme implementada).
O que eu planejei depois disso? armazenamento local & | sessão para permitir um cache caso a caso de iterações necessárias, essencialmente lidando com o problema da "tabela" falado acima. Isso também economizaria muito espaço no banco de dados e no servidor. No entanto, se você escolher localStorage, estará essencialmente sugando espaço no computador de seus usuários simplesmente para armazenar uma lista de números e fazer a tela PARECER mais rápida; no entanto, durante um longo período de tempo com uma necessidade imensa, isso seria lento. Estou pensando que sessionStorage (limpar após a saída de Tab) seria um caminho muito melhor. Possivelmente combinar isso com um servidor de auto-equilíbrio / cache dependente local? O usuário A precisa de X iterações. O usuário B precisa de Y iterações. X + Y / 2 = Quantidade necessária em cache local. Em seguida, basta detectar e mexer nos benchmarks de tempo de carregamento e tempo de execução ao vivo para cada usuário até que ele se ajuste à otimização do próprio site. Obrigado!
Editar 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);
});
Esta edição implementa outra sugestão de Stack e me permite chamar a função como fatorial (true) (5), que foi um dos meus objetivos estabelecidos. : 3 Também removi algumas atribuições desnecessárias e abreviei alguns nomes de variáveis não públicas.
undefined
para 0 !. ES6 permite substituir isNumeric
com Number.isInteger
. Linhas como factorials[0][factorials[1]]=factorials[0][factorial_index]*(factorials[1]+1);
são totalmente ilegíveis.
Aqui está um usando as funções javascript mais recentes preencher , mapear , reduzir e construtor (e sintaxe de seta grande):
Math.factorial = n => n === 0 ? 1 : Array(n).fill(null).map((e,i)=>i+1).reduce((p,c)=>p*c)
Editar: atualizado para lidar com 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);