Procurando uma implementação realmente rápida de função fatorial em JavaScript. Algum sugere?
javascript
math
factorial
Ken
fonte
fonte
Respostas:
Você pode pesquisar por (1 ... 100)! no Wolfram | Alpha para pré-calcular a seqüência fatorial.
Os primeiros 100 números são:
Se você ainda deseja calcular os valores sozinho, pode usar a memoização :
Edição: 21/08/2014
Solução 2
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
Presumo que você usaria algum tipo de encerramento para limitar a visibilidade do nome da variável.
Ref : BigNumber Sandbox : JsFiddle
fonte
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 aBigInt
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
Iterativo
Ao vivo em: http://jsfiddle.net/xMpTv/
Meus resultados mostram:
- Recursivo ~ 150 milissegundos
- Iterativo ~ 5 milissegundos ..
fonte
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):
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.fonte
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 oNumber
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:
Você pode pré-calcular alguns valores para acelerar ainda mais.
fonte
Aqui está minha solução:
É 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) :
fonte
f=n=>n?f(n-1)*n:1
...Apenas uma linha com ES6
Exibir trecho de código
fonte
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):
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):
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).
fonte
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.
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.
fonte
Função fatorial mais rápida
Acho que esta versão baseada em loop pode ser a função fatorial mais rápida.
E aqui está o meu raciocínio:
for
loops ewhile
loops tenham desempenho semelhante, umfor
loop sem uma expressão de inicialização e uma expressão final parece estranho; provavelmente melhor escreverfor(; n > 0;)
comowhile(n > 0)
n
er
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 inteirosfonte
Me 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á:
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 :)
fonte
É muito simples usar ES6
const factorial = n => n ? (n * factorial(n-1)) : 1;
Veja um exemplo aqui
fonte
Aqui está uma solução:
fonte
Usando ES6, você pode alcançá-lo rápido e curto:
fonte
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.
fonte
Esta é uma versão baseada em loop compacto
Ou você pode substituir o objeto Math (versão recursiva):
Ou junte as duas abordagens ...
fonte
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:
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 quandon! > 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.
fonte
Resposta de uma linha:
fonte
Fatorial iterativo com
BigInt
para segurançaEste é um exemplo de uso funcional
BigInt
, porque muitas respostas aqui escapamNumber
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).Exemplo de uso
n
no final de um literal numérico como1303n
indica que é umBigInt
tipo.BigInt
com aNumber
menos que os coage explicitamente, e isso pode causar perda de precisão.fonte
Usando os recursos do ES6, pode escrever código em UMA linha e sem recursão :
Exibir trecho de código
fonte
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.
Para chamá-lo:
fonte
Esta é uma solução iterativa que usa menos espaço na pilha e salva os valores calculados anteriormente de forma autolimitada:
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.
fonte
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.
fonte
n * (n-1) * (n-2) * ... * 1
vez do contrário, você perde até 4 dígitos na precisão para n >> 20.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 comofactorial[n]
, que é um pouco mais eficiente. A execução desses primeiros 100 valores levará menos de um milissegundo em navegadores modernos.fonte
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.
fonte
Aqui está um que eu mesmo fiz, não use números acima de 170 ou abaixo de 2.
fonte
i
e executa muitasNumber
conversões e dá resultados incorretos para 0! (como você afirmou, mas por quê?).Aqui está meu código
fonte
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 comInfinity
.O loop em cache deve ser mais rápido (pelo menos quando chamado várias vezes)
fonte
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:
fonte
undefined
para 0 !. ES6 permite substituirisNumeric
comNumber.isInteger
. Linhas comofactorials[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):
Editar: atualizado para lidar com n === 0
fonte
n === 0
?Math.factorial = n => Array.from({ length: n }).reduce((product, _, i) => product * (i + 1), 1)
fonte