Sto impazzendo: dov'è la funzione Ruby per fattoriale? No, non ho bisogno di implementazioni di tutorial, voglio solo la funzione dalla libreria. Non è in matematica!
Comincio a dubitare, è una funzione di libreria standard?
Sto impazzendo: dov'è la funzione Ruby per fattoriale? No, non ho bisogno di implementazioni di tutorial, voglio solo la funzione dalla libreria. Non è in matematica!
Comincio a dubitare, è una funzione di libreria standard?
(1..6).inject(:*)
che è un po 'più succinto.
(1..num).inject(:*)
fallisce nel caso in cui num == 0
. (1..(num.zero? ? 1 : num)).inject(:*)
fornisce la risposta corretta per il caso 0 e restituisce nil
per i parametri negativi.
Risposte:
Non esiste una funzione fattoriale nella libreria standard.
Math.gamma
metodo, ad esempio stackoverflow.com/a/37352690/407213
Così è meglio
(1..n).inject(:*) || 1
(1..n).reduce(1, :*)
.
Non è nella libreria standard ma puoi estendere la 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 Il fattoriale iterativo è una scelta migliore per ovvi motivi di prestazioni.
Spudoratamente criptato da http://rosettacode.org/wiki/Factorial#Ruby , il mio preferito è
class Integer
def fact
(1..self).reduce(:*) || 1
end
end
>> 400.fact
=> 64034522846623895262347970319503005850702583026002959458684445942802397169186831436278478647463264676294350575035856810848298162883517435228961988646802997937341654150838162426461942352307046244325015114448670890662773914918117331955996440709549671345290477020322434911210797593280795101545372667251627877890009349763765710326350331533965349868386831339352024373788157786791506311858702618270169819740062983025308591298346162272304558339520759611505302236086810433297255194852674432232438669948422404232599805551610635942376961399231917134063858996537970147827206606320217379472010321356624613809077942304597360699567595836096158715129913822286578579549361617654480453222007825818400848436415591229454275384803558374518022675900061399560145595206127211192918105032491008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
Questa implementazione è anche la più veloce tra le varianti elencate in Rosetta Code.
Aggiunto || 1
per gestire il caso zero.
Con grazie e apprezzamento a Mark Thomas , ecco una versione un po 'più efficiente, elegante e oscura:
class Integer
def fact
(2..self).reduce(1,:*)
end
end
reduce
: (1..self).reduce(1,:*)
.
(2..self).reduce(1,:*)
, se la microefficienza è la tua passione :)
In matematica, factorial of n
è solo il gamma function of n+1
(vedi: http://en.wikipedia.org/wiki/Gamma_function )
Ruby deve Math.gamma()
quindi usarlo Math.gamma(n+1)
e restituirlo a un numero intero se lo si desidera.
È inoltre possibile utilizzare una Math.gamma
funzione che si riduce a fattoriale per i parametri interi.
0..22
: MRI Ruby esegue effettivamente una ricerca per quei valori (vedi static const double fact_table[]
nella fonte ). Oltre a ciò, è un'approssimazione. 23!, Ad esempio, richiede una mantissa a 56 bit che è impossibile rappresentare con precisione utilizzando il doppio IEEE 754 che ha una mantissa a 53 bit.
class Integer
def !
(1..self).inject(:*)
end
end
!3 # => 6
!4 # => 24
class Integer ; def ! ; (1..self).inject(:*) ; end ; end
?
a
accade Integer
nel caso di !a
... farlo potrebbe causare l'esistenza di un bug che è molto difficile da dire. Se a
capita di essere un grande numero come 357264543
allora il processore sta entrando in un grande loop e le persone potrebbero chiedersi perché il programma all'improvviso diventa lento
def factorial(n=0)
(1..n).inject(:*)
end
factorial(3)
factorial(11)
L'utilizzo Math.gamma.floor
è un modo semplice per produrre un'approssimazione e poi arrotondarla per difetto al risultato intero corretto. Dovrebbe funzionare per tutti i numeri interi, includere un controllo dell'input se necessario.
n = 22
che cessa di dare una risposta esatta e produce approssimazioni.
Con grande rispetto per tutti coloro che hanno partecipato e hanno speso il loro tempo per aiutarci, vorrei condividere i miei parametri di riferimento delle soluzioni elencate qui. Parametri:
iterazioni = 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)
Per 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)
è anche solo approssimativo per n> 22, quindi potrebbe non essere adatto a tutti i casi d'uso.
Solo un altro modo per farlo, anche se in realtà non è necessario.
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
Probabilmente troverai utile una richiesta di funzionalità Ruby . Contiene una patch non banale che include uno script Bash demo . La differenza di velocità tra un loop ingenuo e la soluzione presentata nel batch può essere letteralmente 100x (cento volte). Scritto tutto in puro Ruby.
Ecco la mia versione che mi sembra chiara anche se non è così pulita.
def factorial(num)
step = 0
(num - 1).times do (step += 1 ;num *= step) end
return num
end
Questa era la mia linea di test IRB che mostrava ogni passaggio.
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 un altro modo per farlo:
# fact(n) => Computes the Factorial of "n" = n!
def fact(n) (1..n).inject(1) {|r,i| r*i }end
fact(6) => 720
Perché la libreria standard richiederebbe un metodo fattoriale, quando esiste un iteratore integrato per questo scopo esatto? Si chiama upto
.
No, non è necessario utilizzare la ricorsione, come mostrano tutte queste altre risposte.
def fact(n)
n == 0 ? 1 : n * fact(n - 1)
end
Piuttosto, l'iteratore integrato fino a può essere utilizzato per calcolare i fattoriali:
factorial = 1
1.upto(10) {|x| factorial *= x }
factorial
=> 3628800
6.downto(1).inject(:*)