Estou ficando louco: Onde está a função Ruby para fatorial? Não, não preciso de implementações de tutorial, só quero a função da biblioteca. Não está na matemática!
Estou começando a duvidar, é uma função de biblioteca padrão?
@mckeed: Ou (1..6).inject(:*)que é um pouco mais sucinto.
sepp2k
8
por que você esperaria que houvesse um?
Presidente James K. Polk,
4
Eu me pergunto qual é o status das bibliotecas de matemática e ciências para Ruby.
Andrew Grimm
5
Apenas uma nota sobre os exemplos fornecidos usando injetar. (1..num).inject(:*)falha para o caso em que num == 0. (1..(num.zero? ? 1 : num)).inject(:*)fornece a resposta correta para o caso 0 e retorna nilpara os parâmetros negativos.
Ou especificar o valor inicial diretamente: (1..n).reduce(1, :*).
Andrew Marshall
77
Não está na biblioteca padrão, mas você pode estender a classe Integer.
classIntegerdef factorial_recursive
self<=1?1:self*(self-1).factorial
enddef factorial_iterative
f =1;for i in1..self; f *= i;end; f
endalias:factorial :factorial_iterative
end
NB Fatorial iterativo é a melhor escolha por razões óbvias de desempenho.
Que diabos isso significa?! sim, é rápido, mas é muito incomum
niccolo m.
3
também é incorreto para 0! - deve ser algo como: if self <= 1; 1; outro; (1..se) .reduzir (: *); fim
Tarmo
8
@allen - Não culpe a linguagem se você não consegue entendê-la. Significa simplesmente pegar o intervalo 1 para self e, em seguida, remover o primeiro elemento (1) dele (ou seja, isso é o que significa reduzir na programação funcional). Em seguida, remova o primeiro elemento do que resta (2) e multiplique (: *) todos juntos. Agora remova o primeiro elemento do que resta (3) e multiplique-o pelo total corrente. Continue até que não haja mais nada (ou seja, você manipulou toda a gama). Se a redução falhar (porque o array está vazio no caso de 0!), Então apenas retorne 1 de qualquer maneira.
SDJMcHattie
Você também pode lidar com o caso de zero especificando o valor inicial em reduce: (1..self).reduce(1,:*).
Mark Thomas
3
Na verdade, você pode usar (2..self).reduce(1,:*), se micro-eficiência for o seu lugar :)
Mark Thomas
14
Você também pode usar a Math.gammafunção que se resume a fatorial para parâmetros inteiros.
Dos documentos: "Observe que gamma (n) é igual a fact (n-1) para o inteiro n> 0. No entanto, gamma (n) retorna float e pode ser uma aproximação". Se levarmos isso em consideração, funciona, mas a solução de redução parece muito mais direta.
Michael Kohl
Obrigado por isso! Meu instinto diz para usar a biblioteca padrão em vez de um redução personalizada sempre que possível. A criação de perfil pode sugerir o contrário.
David J.
2
Nota: É O (1) e preciso para 0..22: MRI Ruby realmente executa uma pesquisa para esses valores (veja static const double fact_table[]na fonte ). Além disso, é uma aproximação. 23 !, por exemplo, requer uma mantissa de 56 bits que é impossível representar precisamente usando o duplo IEEE 754 que tem mantissas de 53 bits.
O que há de errado class Integer ; def ! ; (1..self).inject(:*) ; end ; end?
Aleksei Matiushkin
@mudasobwa Eu gosto, refatorei para simplificar.
jasonleonhard
4
Eu respeitosamente sugeriria que substituir um método de instância incorporado em todos os objetos Ruby para retornar um valor verdadeiro, ao invés de um falso, pode não fazer você muitos amigos.
MatzFan
Pode ser muito perigoso fazer com que o operador de negação se torne outra coisa quando aacontece de estar Integerno caso de !a... fazer isso pode causar a existência de um bug que é muito difícil de dizer. Se aacontecer de ser um grande número, como 357264543então o processador está entrando em um grande loop e as pessoas podem se perguntar por que o programa de repente fica lento
polaridade
Essa resposta foi mais apenas uma coisa legal de compartilhar do que um exemplo prático de usar.
Usar Math.gamma.flooré uma maneira fácil de produzir uma aproximação e arredondar de volta para o resultado inteiro correto. Deve funcionar para todos os inteiros, inclua uma verificação de entrada se necessário.
Correção: Depois n = 22que deixa de dar uma resposta exata e produz aproximações.
Ayarch
2
Com muito respeito a todos que participaram e despenderam seu tempo nos ajudando, gostaria de compartilhar meus benchmarks das soluções listadas aqui. Params:
iterações = 1000
n = 6
user system total real
Math.gamma(n+1)0.0003830.0001060.000489(0.000487)(1..n).inject(:*)||10.0039860.0000000.003986(0.003987)(1..n).reduce(1,:*)0.0039260.0000000.003926(0.004023)1.upto(n){|x| factorial *= x }0.0037480.0117340.015482(0.022795)
Para n = 10
user system total real
0.0003780.0001020.000480(0.000477)0.0044690.0000070.004476(0.004491)0.0045320.0000240.004556(0.005119)0.0277200.0112110.038931(0.058309)
É importante notar que o mais rápido Math.gamma(n+1)também é apenas aproximado para n> 22, portanto, pode não ser adequado para todos os casos de uso.
Neil Slater de
1
Apenas outra maneira de fazer isso, embora realmente não seja necessário.
classFactorial
attr_reader :num
def initialize(num)@num= num
enddef find_factorial
(1..num).inject(:*)||1endend
number =Factorial.new(8).find_factorial
puts number
Você provavelmente achará útil uma solicitação de recurso Ruby . Ele contém um patch não trivial que inclui um script Bash de demonstração . A diferença de velocidade entre um loop ingênuo e a solução apresentada no lote pode ser literalmente 100x (cem vezes). Escrito tudo em Ruby puro.
classIntegerdef factorial
returnself<0?false:self==0?1:self.downto(1).inject(:*)#Not sure what other libraries say, but my understanding is that factorial of #anything less than 0 does not exist.endend
def factorial(number)
number = number.to_i
number_range =(number).downto(1).to_a
factorial = number_range.inject(:*)
puts "The factorial of #{number} is #{factorial}"end
factorial(#number)
6.downto(1).inject(:*)
(1..6).inject(:*)
que é um pouco mais sucinto.(1..num).inject(:*)
falha para o caso em quenum == 0
.(1..(num.zero? ? 1 : num)).inject(:*)
fornece a resposta correta para o caso 0 e retornanil
para os parâmetros negativos.Respostas:
Não há função fatorial na biblioteca padrão.
fonte
Math.gamma
método, por exemplo, stackoverflow.com/a/37352690/407213Assim é melhor
fonte
(1..n).reduce(1, :*)
.Não está na biblioteca padrão, mas você pode estender a classe Integer.
NB Fatorial iterativo é a melhor escolha por razões óbvias de desempenho.
fonte
Descaradamente copiado de http://rosettacode.org/wiki/Factorial#Ruby , meu favorito pessoal é
Essa implementação também é a mais rápida entre as variantes listadas no Rosetta Code.
atualização # 1
Adicionado
|| 1
para lidar com o caso zero.atualização # 2
Com agradecimento e apreço a Mark Thomas , aqui está uma versão um pouco mais eficiente, elegante e obscura:
fonte
reduce
:(1..self).reduce(1,:*)
.(2..self).reduce(1,:*)
, se micro-eficiência for o seu lugar :)Você também pode usar a
Math.gamma
função que se resume a fatorial para parâmetros inteiros.fonte
0..22
: MRI Ruby realmente executa uma pesquisa para esses valores (vejastatic const double fact_table[]
na fonte ). Além disso, é uma aproximação. 23 !, por exemplo, requer uma mantissa de 56 bits que é impossível representar precisamente usando o duplo IEEE 754 que tem mantissas de 53 bits.Em matemática,
factorial of n
é apenas ogamma function of n+1
(veja: http://en.wikipedia.org/wiki/Gamma_function )
Ruby
Math.gamma()
então apenas usaMath.gamma(n+1)
e converte de volta para um inteiro, se desejar.fonte
exemplos
fonte
class Integer ; def ! ; (1..self).inject(:*) ; end ; end
?a
acontece de estarInteger
no caso de!a
... fazer isso pode causar a existência de um bug que é muito difícil de dizer. Sea
acontecer de ser um grande número, como357264543
então o processador está entrando em um grande loop e as pessoas podem se perguntar por que o programa de repente fica lentoeu faria
fonte
Acabei de escrever o meu próprio:
Além disso, você pode definir um fatorial de queda:
fonte
Basta chamar esta função
exemplos
fonte
Usar
Math.gamma.floor
é uma maneira fácil de produzir uma aproximação e arredondar de volta para o resultado inteiro correto. Deve funcionar para todos os inteiros, inclua uma verificação de entrada se necessário.fonte
n = 22
que deixa de dar uma resposta exata e produz aproximações.Com muito respeito a todos que participaram e despenderam seu tempo nos ajudando, gostaria de compartilhar meus benchmarks das soluções listadas aqui. Params:
iterações = 1000
n = 6
Para n = 10
fonte
Math.gamma(n+1)
também é apenas aproximado para n> 22, portanto, pode não ser adequado para todos os casos de uso.Apenas outra maneira de fazer isso, embora realmente não seja necessário.
fonte
Você provavelmente achará útil uma solicitação de recurso Ruby . Ele contém um patch não trivial que inclui um script Bash de demonstração . A diferença de velocidade entre um loop ingênuo e a solução apresentada no lote pode ser literalmente 100x (cem vezes). Escrito tudo em Ruby puro.
fonte
Aqui está minha versão parece ser clara para mim, embora não seja tão limpa.
Esta foi a minha linha de teste irb que mostrou cada etapa.
fonte
fonte
E ainda outra forma (=
fonte
Só mais uma maneira de fazer isso:
fonte
Por que a biblioteca padrão exigiria um método fatorial, quando há um iterador embutido para esse propósito exato? É chamado
upto
.Não, você não precisa usar recursão, como todas essas outras respostas mostram.
Em vez disso, o iterador integrado upto pode ser usado para calcular fatoriais:
fonte