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?
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?
(1..6).inject(:*)
que é um pouco mais sucinto.
(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 nil
para os parâmetros negativos.
Respostas:
Não há função fatorial na biblioteca padrão.
Math.gamma
método, por exemplo, stackoverflow.com/a/37352690/407213
Assim é melhor
(1..n).inject(:*) || 1
(1..n).reduce(1, :*)
.
Não está na biblioteca padrão, mas você pode estender a classe Integer.
class Integer
def factorial_recursive
self <= 1 ? 1 : self * (self - 1).factorial
end
def factorial_iterative
f = 1; for i in 1..self; f *= i; end; f
end
alias :factorial :factorial_iterative
end
NB Fatorial iterativo é a melhor escolha por razões óbvias de desempenho.
Descaradamente copiado de http://rosettacode.org/wiki/Factorial#Ruby , meu favorito pessoal é
class Integer
def fact
(1..self).reduce(:*) || 1
end
end
>> 400.fact
=> 64034522846623895262347970319503005850702583026002959458684445942802397169186831436278478647463264676294350575035856810848298162883517435228961988646802997937341654150838162426461942352307046244325015114448670890662773914918117331955996440709549671345290477020322434911210797593280795101545372667251627877890009349763765710326350331533965349868386831339352024373788157786791506311858702618270169819740062983025308591298346162272304558339520759611505302236086810433297255194852674432232438669948422404232599805551610635942376961399231917134063858996537970147827206606320217379472010321356624613809077942304597360699567595836096158715129913822286578579549361617654480453222007825818400848436415591229454275384803558374518022675900061399560145595206127211192918105032491008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
Essa implementação também é a mais rápida entre as variantes listadas no Rosetta Code.
Adicionado || 1
para lidar com o caso zero.
Com agradecimento e apreço a Mark Thomas , aqui está uma versão um pouco mais eficiente, elegante e obscura:
class Integer
def fact
(2..self).reduce(1,:*)
end
end
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.
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.
Em matemática, factorial of n
é apenas o gamma function of n+1
(veja: http://en.wikipedia.org/wiki/Gamma_function )
Ruby Math.gamma()
então apenas usa Math.gamma(n+1)
e converte de volta para um inteiro, se desejar.
class Integer
def !
(1..self).inject(:*)
end
end
!3 # => 6
!4 # => 24
class Integer ; def ! ; (1..self).inject(:*) ; end ; end
?
a
acontece de estar Integer
no caso de !a
... fazer isso pode causar a existência de um bug que é muito difícil de dizer. Se a
acontecer de ser um grande número, como 357264543
então o processador está entrando em um grande loop e as pessoas podem se perguntar por que o programa de repente fica lento
def factorial(n=0)
(1..n).inject(:*)
end
factorial(3)
factorial(11)
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.
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
user system total real
Math.gamma(n+1) 0.000383 0.000106 0.000489 ( 0.000487)
(1..n).inject(:*) || 1 0.003986 0.000000 0.003986 ( 0.003987)
(1..n).reduce(1, :*) 0.003926 0.000000 0.003926 ( 0.004023)
1.upto(n) {|x| factorial *= x } 0.003748 0.011734 0.015482 ( 0.022795)
Para n = 10
user system total real
0.000378 0.000102 0.000480 ( 0.000477)
0.004469 0.000007 0.004476 ( 0.004491)
0.004532 0.000024 0.004556 ( 0.005119)
0.027720 0.011211 0.038931 ( 0.058309)
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.
class Factorial
attr_reader :num
def initialize(num)
@num = num
end
def find_factorial
(1..num).inject(:*) || 1
end
end
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.
Aqui está minha versão parece ser clara para mim, embora não seja tão limpa.
def factorial(num)
step = 0
(num - 1).times do (step += 1 ;num *= step) end
return num
end
Esta foi a minha linha de teste irb que mostrou cada etapa.
num = 8;step = 0;(num - 1).times do (step += 1 ;num *= step; puts num) end;num
class Integer
def factorial
return self < 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.
end
end
Só mais uma maneira de fazer isso:
# fact(n) => Computes the Factorial of "n" = n!
def fact(n) (1..n).inject(1) {|r,i| r*i }end
fact(6) => 720
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.
def fact(n)
n == 0 ? 1 : n * fact(n - 1)
end
Em vez disso, o iterador integrado upto pode ser usado para calcular fatoriais:
factorial = 1
1.upto(10) {|x| factorial *= x }
factorial
=> 3628800
6.downto(1).inject(:*)