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?
@mckeed: O (1..6).inject(:*)que es un poco más sucinto.
sepp2k
8
¿Por qué esperarías que hubiera uno?
Presidente James K. Polk
4
Me pregunto cuál es el estado de las bibliotecas de matemáticas y ciencias para Ruby.
Andrew Grimm
5
Solo una nota sobre los ejemplos proporcionados usando inject. (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 nillos parámetros negativos.
Yogh
Respuestas:
136
No hay función factorial en la biblioteca estándar.
O especificar el valor inicial directamente: (1..n).reduce(1, :*).
Andrew Marshall
77
No está en la biblioteca estándar, pero puede extender la clase Integer.
classIntegerdeffactorial_recursiveself <= 1 ? 1 : self * (self - 1).factorial
enddeffactorial_iterative
f = 1; for i in1..self; f *= i; end; f
endalias:factorial:factorial_iterativeend
NB El factorial iterativo es una mejor opción por razones obvias de rendimiento.
¡¿Qué diablos significa eso?! sí, es rápido pero muy poco amigable
niccolo m.
3
¡también es incorrecto para 0! - debería ser algo como: if self <= 1; 1; más; (1..auto) .reducir (: *); fin
Tarmo
8
@allen: no culpes al idioma si no puedes entenderlo. Simplemente significa, tome el rango 1 a sí mismo, luego elimine el primer elemento (1) (es decir, eso es lo que reduce los medios en la programación funcional). Luego elimine el primer elemento de lo que queda (2) y multiplíquelos (: *) juntos. Ahora elimine el primer elemento de lo que queda (3) y multiplíquelo por el total acumulado. Continúe hasta que no quede nada (es decir, haya manejado todo el rango). Si la reducción falla (¡porque la matriz está vacía en el caso de 0!), Devuelva 1 de todos modos.
SDJMcHattie
También puede manejar el caso cero especificando el valor inicial en reduce: (1..self).reduce(1,:*).
Mark Thomas
3
En realidad, puede usarlo (2..self).reduce(1,:*), si lo suyo es la microeficiencia :)
De los documentos: "Tenga en cuenta que gamma (n) es lo mismo que fact (n-1) para el entero n> 0. Sin embargo, gamma (n) devuelve float y puede ser una aproximación". Si uno tiene eso en cuenta, funciona, pero la solución de reducción parece mucho más sencilla.
Michael Kohl
¡Gracias por esto! Mi instinto dice que se use para la biblioteca estándar en lugar de una reducción escrita personalizada siempre que sea posible. La elaboración de perfiles podría sugerir lo contrario.
David J.
2
Nota: Es O (1) y precisa para 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.
¿Qué pasa con class Integer ; def ! ; (1..self).inject(:*) ; end ; end?
Aleksei Matiushkin
@mudasobwa Me gusta, lo he refactorizado por simplicidad.
Jasonleonhard
4
Respetuosamente sugeriría que anular un método de instancia incorporado en todos los objetos Ruby para devolver un valor verdadero, en lugar de uno falso, puede que no le haga muchos amigos.
MatzFan
Puede ser realmente peligroso hacer que el operador de negación se convierta en otra cosa cuando asucede Integeren el caso de !a... hacerlo puede causar que exista un error que es muy difícil de decir. Si aresulta ser un número grande, 357264543entonces el procesador entra en un gran bucle y la gente puede preguntarse por qué el programa de repente se vuelve lento
polaridad
Esta respuesta fue más algo interesante para compartir que un ejemplo práctico para usar.
Usar Math.gamma.floores 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.
Corrección: Después n = 22deja de dar una respuesta exacta y produce aproximaciones.
Ayarch
2
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.0001060.000489 ( 0.000487)
(1..n).inject(:*) ||10.003986 0.0000000.003986 ( 0.003987)
(1..n).reduce(1, :*) 0.003926 0.0000000.003926 ( 0.004023)
1.upto(n) {|x| factorial *= x } 0.003748 0.0117340.015482 ( 0.022795)
Para n = 10
user system total real
0.000378 0.0001020.000480 ( 0.000477)
0.004469 0.0000070.004476 ( 0.004491)
0.0045320.0000240.004556 ( 0.005119)
0.0277200.0112110.038931 ( 0.058309)
Cabe señalar que el más rápido 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.
Neil Slater
1
Solo otra forma de hacerlo, aunque realmente no es necesario.
classFactorialattr_reader:numdefinitialize(num)
@num = num
enddeffind_factorial
(1..num).inject(:*) ||1endend
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.
classIntegerdeffactorialreturnself < 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
deffactorial(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 es un poco más sucinto.(1..num).inject(:*)
falla para el caso dondenum == 0
.(1..(num.zero? ? 1 : num)).inject(:*)
da la respuesta correcta para el caso 0 y devuelvenil
los parámetros negativos.Respuestas:
No hay función factorial en la biblioteca estándar.
fuente
Math.gamma
método, por ejemplo, stackoverflow.com/a/37352690/407213Como si esto fuera mejor
(1..n).inject(:*) || 1
fuente
(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.
fuente
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.
actualización # 1
Agregado
|| 1
para manejar el caso cero.actualización # 2
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
fuente
reduce
:(1..self).reduce(1,:*)
.(2..self).reduce(1,:*)
, si lo suyo es la microeficiencia :)En matemáticas,
factorial of n
es solo elgamma function of n+1
(ver: http://en.wikipedia.org/wiki/Gamma_function )
Ruby solo tiene
Math.gamma()
que usarloMath.gamma(n+1)
y convertirlo en un número entero si lo desea.fuente
También puede usar la
Math.gamma
función que se reduce a factorial para parámetros enteros.fuente
0..22
: MRI Ruby en realidad realiza una búsqueda de esos valores (verstatic 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
ejemplos
!3 # => 6 !4 # => 24
fuente
class Integer ; def ! ; (1..self).inject(:*) ; end ; end
?a
sucedeInteger
en el caso de!a
... hacerlo puede causar que exista un error que es muy difícil de decir. Sia
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 lentoyo lo haría
(1..n).inject(1, :*)
fuente
Acabo de escribir el mío:
def fact(n) if n<= 1 1 else n * fact( n - 1 ) end end
Además, puede definir un factorial descendente:
def fall_fact(n,k) if k <= 0 1 else n*fall_fact(n - 1, k - 1) end end
fuente
Solo llama a esta función
def factorial(n=0) (1..n).inject(:*) end
ejemplos
factorial(3) factorial(11)
fuente
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.fuente
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)
fuente
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
fuente
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.
fuente
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
fuente
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
fuente
Y aún otra forma (=
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)
fuente
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
fuente
¿Por qué la biblioteca estándar requeriría un método factorial, cuando hay un iterador incorporado para este propósito exacto? Se llama
upto
.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
fuente