Me estoy volviendo loco: ¿Dónde está la función Ruby para factorial? No, no necesito implementaciones de tutoriales, solo quiero la función de la biblioteca. ¡No está en matemáticas!
Estoy empezando a dudar, ¿es una función de biblioteca estándar?
Me estoy volviendo loco: ¿Dónde está la función Ruby para factorial? No, no necesito implementaciones de tutoriales, solo quiero la función de la biblioteca. ¡No está en matemáticas!
Estoy empezando a dudar, ¿es una función de biblioteca estándar?
(1..6).inject(:*)
que es un poco más sucinto.
(1..num).inject(:*)
falla para el caso donde num == 0
. (1..(num.zero? ? 1 : num)).inject(:*)
da la respuesta correcta para el caso 0 y devuelve nil
los parámetros negativos.
Respuestas:
No hay función factorial en la biblioteca estándar.
Math.gamma
método, por ejemplo, stackoverflow.com/a/37352690/407213
Como si esto fuera mejor
(1..n).inject(:*) || 1
(1..n).reduce(1, :*)
.
No está en la biblioteca estándar, pero puede extender la clase 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 El factorial iterativo es una mejor opción por razones obvias de rendimiento.
Desvergonzadamente extraído de http://rosettacode.org/wiki/Factorial#Ruby , mi favorito personal es
class Integer
def fact
(1..self).reduce(:*) || 1
end
end
>> 400.fact
=> 64034522846623895262347970319503005850702583026002959458684445942802397169186831436278478647463264676294350575035856810848298162883517435228961988646802997937341654150838162426461942352307046244325015114448670890662773914918117331955996440709549671345290477020322434911210797593280795101545372667251627877890009349763765710326350331533965349868386831339352024373788157786791506311858702618270169819740062983025308591298346162272304558339520759611505302236086810433297255194852674432232438669948422404232599805551610635942376961399231917134063858996537970147827206606320217379472010321356624613809077942304597360699567595836096158715129913822286578579549361617654480453222007825818400848436415591229454275384803558374518022675900061399560145595206127211192918105032491008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
Esta implementación también resulta ser la más rápida entre las variantes enumeradas en el Código Rosetta.
Agregado || 1
para manejar el caso cero.
Con agradecimiento y aprecio a Mark Thomas , aquí hay una versión que es un poco más eficiente, elegante y oscura:
class Integer
def fact
(2..self).reduce(1,:*)
end
end
reduce
: (1..self).reduce(1,:*)
.
(2..self).reduce(1,:*)
, si lo suyo es la microeficiencia :)
En matemáticas, factorial of n
es solo el gamma function of n+1
(ver: http://en.wikipedia.org/wiki/Gamma_function )
Ruby solo tiene Math.gamma()
que usarlo Math.gamma(n+1)
y convertirlo en un número entero si lo desea.
También puede usar la Math.gamma
función que se reduce a factorial para parámetros enteros.
0..22
: MRI Ruby en realidad realiza una búsqueda de esos valores (ver static const double fact_table[]
en la fuente ). Más allá de eso, es una aproximación. 23 !, por ejemplo, requiere una mantisa de 56 bits que es imposible de representar con precisión usando el doble IEEE 754 que tiene mantisas de 53 bits.
class Integer
def !
(1..self).inject(:*)
end
end
!3 # => 6
!4 # => 24
class Integer ; def ! ; (1..self).inject(:*) ; end ; end
?
a
sucede Integer
en el caso de !a
... hacerlo puede causar que exista un error que es muy difícil de decir. Si a
resulta ser un número grande, 357264543
entonces el procesador entra en un gran bucle y la gente puede preguntarse por qué el programa de repente se vuelve lento
def factorial(n=0)
(1..n).inject(:*)
end
factorial(3)
factorial(11)
Usar Math.gamma.floor
es una manera fácil de producir una aproximación y luego redondearla hacia abajo al resultado entero correcto. Debería funcionar para todos los enteros, incluya una verificación de entrada si es necesario.
n = 22
deja de dar una respuesta exacta y produce aproximaciones.
Con mucho respeto a todos los que participaron y dedicaron su tiempo a ayudarnos, me gustaría compartir mis puntos de referencia de las soluciones enumeradas aquí. Parámetros:
iteraciones = 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)
también es solo aproximado para n> 22, por lo que puede no ser adecuado para todos los casos de uso.
Solo otra forma de hacerlo, aunque realmente no es necesario.
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
Probablemente encuentre útil una solicitud de función de Ruby . Contiene un parche no trivial que incluye un script de demostración Bash . La diferencia de velocidad entre un bucle ingenuo y la solución presentada en el lote puede ser literalmente 100x (cien veces). Escrito todo en Ruby puro.
Aquí está mi versión que me parece clara a pesar de que no es tan limpia.
def factorial(num)
step = 0
(num - 1).times do (step += 1 ;num *= step) end
return num
end
Esta fue mi línea de prueba de irb que mostró cada paso.
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
Solo una forma más de hacerlo:
# fact(n) => Computes the Factorial of "n" = n!
def fact(n) (1..n).inject(1) {|r,i| r*i }end
fact(6) => 720
¿Por qué la biblioteca estándar requeriría un método factorial, cuando hay un iterador incorporado para este propósito exacto? Se llamaupto
.
No, no es necesario utilizar la recursividad, como muestran todas estas otras respuestas.
def fact(n)
n == 0 ? 1 : n * fact(n - 1)
end
Más bien, el iterador incorporado hasta se puede usar para calcular factoriales:
factorial = 1
1.upto(10) {|x| factorial *= x }
factorial
=> 3628800
6.downto(1).inject(:*)