@mckeed: Lub (1..6).inject(:*)który jest nieco bardziej zwięzły.
wrzesień
8
dlaczego miałbyś się spodziewać, że taki będzie?
Prezydent James K. Polk
4
Zastanawiam się, jaki jest status bibliotek matematycznych i naukowych dla Rubiego.
Andrew Grimm
5
Tylko uwaga na podanych przykładach z użyciem inject. (1..num).inject(:*)zawodzi w przypadku, gdy num == 0. (1..(num.zero? ? 1 : num)).inject(:*)podaje poprawną odpowiedź dla przypadku 0 i zwraca nildla parametrów ujemnych.
Lub określić wartość początkową bezpośrednio: (1..n).reduce(1, :*).
Andrew Marshall,
77
Nie ma jej w bibliotece standardowej, ale możesz rozszerzyć klasę 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
Uwaga: Silnia iteracyjna jest lepszym wyborem z oczywistych powodów dotyczących wydajności.
co to do cholery znaczy ?! tak, jest szybki, ale jest bardzo nieprzyjazny
niccolo m.
3
jest również niepoprawne dla 0! - powinno wyglądać mniej więcej tak: if self <= 1; 1; jeszcze; (1.. siebie) .reduce (: *); koniec
Tarmo
8
@allen - nie obwiniaj języka, jeśli go nie rozumiesz. Oznacza to po prostu, weź zakres 1 do siebie, a następnie usuń z niego pierwszy element (1) (tj. To jest właśnie to, co redukuje środki w programowaniu funkcjonalnym). Następnie usuń pierwszy element z tego, co zostało (2) i pomnóż (: *) te razem. Teraz usuń pierwszy element z tego, co zostało (3) i pomnóż go przez sumę bieżącą. Kontynuuj, aż nic nie zostanie (tj. Obsłużyłeś cały zakres). Jeśli redukcja się nie powiedzie (ponieważ tablica jest pusta w przypadku 0!), I tak po prostu zwróć 1.
SDJMcHattie
Można również obsługiwać sprawę zerowej określając wartość początkową w reduce: (1..self).reduce(1,:*).
Mark Thomas
3
Właściwie możesz użyć (2..self).reduce(1,:*), jeśli mikroefektywność jest twoją sprawą :)
Z dokumentacji: „Zwróć uwagę, że gamma (n) jest tym samym, co fakt (n-1) dla liczby całkowitej n> 0. Jednak gamma (n) zwraca wartość zmiennoprzecinkową i może być przybliżeniem”. Jeśli weźmie się to pod uwagę, to działa, ale rozwiązanie redukujące wydaje się o wiele prostsze.
Michael Kohl
Dzięki za to! Moje przeczucie mówi, żebym korzystał z biblioteki standardowej zamiast niestandardowej redukcji, jeśli to możliwe. Profilowanie może sugerować coś innego.
David J.
2
Uwaga: to O (1) i precyzyjna 0..22: MRI Ruby faktycznie wykonuje odnośnika do tych wartości (patrz static const double fact_table[]w źródle ). Poza tym jest to przybliżenie. 23!, Na przykład, wymaga 56-bitowej mantysy, której nie można precyzyjnie odwzorować przy użyciu podwójnego IEEE 754, który ma 53-bitowe mantysy.
Co jest nie tak class Integer ; def ! ; (1..self).inject(:*) ; end ; end?
Aleksei Matiushkin
@mudasobwa Podoba mi się, przerobiłem dla uproszczenia.
jasonleonhard
4
Z całym szacunkiem zasugerowałbym, że nadpisanie metody instancji zawartej we wszystkich obiektach Ruby w celu zwrócenia prawdziwej wartości, a nie fałszywej, może nie przysporzyć Ci wielu przyjaciół.
MatzFan
To może być naprawdę niebezpieczne, jeśli operator negacji stanie się kimś innym, gdy atak się stanie Integerw przypadku !a... może to spowodować powstanie błędu, który jest bardzo trudny do stwierdzenia. Jeśli azdarzy się, że jest to duża liczba, taka jak 357264543wtedy, procesor wpada w dużą pętlę i ludzie mogą się zastanawiać, dlaczego program nagle staje się wolny
niepolarność
Ta odpowiedź była raczej fajną rzeczą do udostępnienia niż praktycznym przykładem do wykorzystania.
Użycie Math.gamma.floorjest łatwym sposobem uzyskania przybliżenia, a następnie zaokrąglenia go z powrotem do prawidłowego wyniku będącego liczbą całkowitą. Powinien działać dla wszystkich liczb całkowitych, w razie potrzeby uwzględnij sprawdzenie danych wejściowych.
Korekta: po n = 22tym, jak przestaje udzielać dokładnej odpowiedzi i tworzy przybliżenia.
Ayarch
2
Z całym szacunkiem dla wszystkich, którzy uczestniczyli i poświęcili nam swój czas, chciałbym podzielić się moimi wzorcami rozwiązań wymienionych tutaj. Parametry:
iteracje = 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)
Dla 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)
Warto zauważyć, że najszybszy Math.gamma(n+1)jest również przybliżony tylko dla n> 22, więc może nie nadawać się do wszystkich przypadków użycia.
Neil Slater
1
Po prostu inny sposób na zrobienie tego, chociaż naprawdę nie jest to konieczne.
classFactorialattr_reader:numdefinitialize(num)
@num = num
enddeffind_factorial
(1..num).inject(:*) ||1endend
number = Factorial.new(8).find_factorial
puts number
Prawdopodobnie okaże się przydatna prośba o funkcję Rubiego . Zawiera nietrywialną łatkę, która zawiera skrypt demonstracyjny Bash . Różnica prędkości między naiwną pętlą a rozwiązaniem przedstawionym w partii może wynosić dosłownie 100x (stukrotność). Napisane wszystko w czystym Ruby.
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(:*)
który jest nieco bardziej zwięzły.(1..num).inject(:*)
zawodzi w przypadku, gdynum == 0
.(1..(num.zero? ? 1 : num)).inject(:*)
podaje poprawną odpowiedź dla przypadku 0 i zwracanil
dla parametrów ujemnych.Odpowiedzi:
W bibliotece standardowej nie ma funkcji silni.
źródło
Math.gamma
metodę, np. Stackoverflow.com/a/37352690/407213Tak jest lepiej
(1..n).inject(:*) || 1
źródło
(1..n).reduce(1, :*)
.Nie ma jej w bibliotece standardowej, ale możesz rozszerzyć klasę 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
Uwaga: Silnia iteracyjna jest lepszym wyborem z oczywistych powodów dotyczących wydajności.
źródło
Bezwstydnie szopka z http://rosettacode.org/wiki/Factorial#Ruby , moim ulubionym jest
class Integer def fact (1..self).reduce(:*) || 1 end end >> 400.fact => 64034522846623895262347970319503005850702583026002959458684445942802397169186831436278478647463264676294350575035856810848298162883517435228961988646802997937341654150838162426461942352307046244325015114448670890662773914918117331955996440709549671345290477020322434911210797593280795101545372667251627877890009349763765710326350331533965349868386831339352024373788157786791506311858702618270169819740062983025308591298346162272304558339520759611505302236086810433297255194852674432232438669948422404232599805551610635942376961399231917134063858996537970147827206606320217379472010321356624613809077942304597360699567595836096158715129913822286578579549361617654480453222007825818400848436415591229454275384803558374518022675900061399560145595206127211192918105032491008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
Ta implementacja jest również najszybsza spośród wariantów wymienionych w kodzie Rosetta.
aktualizacja nr 1
Dodano
|| 1
do obsługi przypadku zerowego.aktualizacja nr 2
Z podziękowaniami i uznaniem dla Marka Thomasa , oto wersja, która jest nieco bardziej wydajna, elegancka i niejasna:
class Integer def fact (2..self).reduce(1,:*) end end
źródło
reduce
:(1..self).reduce(1,:*)
.(2..self).reduce(1,:*)
, jeśli mikroefektywność jest twoją sprawą :)W matematyce
factorial of n
to tylkogamma function of n+1
(patrz: http://en.wikipedia.org/wiki/Gamma_function )
Ruby ma
Math.gamma()
więc po prostu użyjMath.gamma(n+1)
i w razie potrzeby rzuć go z powrotem na liczbę całkowitą.źródło
Możesz również użyć
Math.gamma
funkcji, która sprowadza się do silni dla parametrów całkowitych.źródło
0..22
: MRI Ruby faktycznie wykonuje odnośnika do tych wartości (patrzstatic const double fact_table[]
w źródle ). Poza tym jest to przybliżenie. 23!, Na przykład, wymaga 56-bitowej mantysy, której nie można precyzyjnie odwzorować przy użyciu podwójnego IEEE 754, który ma 53-bitowe mantysy.class Integer def ! (1..self).inject(:*) end end
przykłady
!3 # => 6 !4 # => 24
źródło
class Integer ; def ! ; (1..self).inject(:*) ; end ; end
?a
tak się stanieInteger
w przypadku!a
... może to spowodować powstanie błędu, który jest bardzo trudny do stwierdzenia. Jeślia
zdarzy się, że jest to duża liczba, taka jak357264543
wtedy, procesor wpada w dużą pętlę i ludzie mogą się zastanawiać, dlaczego program nagle staje się wolnychciałbym zrobić
(1..n).inject(1, :*)
źródło
Właśnie napisałem własne:
def fact(n) if n<= 1 1 else n * fact( n - 1 ) end end
Możesz także zdefiniować silnię opadającą:
def fall_fact(n,k) if k <= 0 1 else n*fall_fact(n - 1, k - 1) end end
źródło
Po prostu wywołaj tę funkcję
def factorial(n=0) (1..n).inject(:*) end
przykłady
factorial(3) factorial(11)
źródło
Użycie
Math.gamma.floor
jest łatwym sposobem uzyskania przybliżenia, a następnie zaokrąglenia go z powrotem do prawidłowego wyniku będącego liczbą całkowitą. Powinien działać dla wszystkich liczb całkowitych, w razie potrzeby uwzględnij sprawdzenie danych wejściowych.źródło
n = 22
tym, jak przestaje udzielać dokładnej odpowiedzi i tworzy przybliżenia.Z całym szacunkiem dla wszystkich, którzy uczestniczyli i poświęcili nam swój czas, chciałbym podzielić się moimi wzorcami rozwiązań wymienionych tutaj. Parametry:
iteracje = 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)
Dla 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)
źródło
Math.gamma(n+1)
jest również przybliżony tylko dla n> 22, więc może nie nadawać się do wszystkich przypadków użycia.Po prostu inny sposób na zrobienie tego, chociaż naprawdę nie jest to konieczne.
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
źródło
Prawdopodobnie okaże się przydatna prośba o funkcję Rubiego . Zawiera nietrywialną łatkę, która zawiera skrypt demonstracyjny Bash . Różnica prędkości między naiwną pętlą a rozwiązaniem przedstawionym w partii może wynosić dosłownie 100x (stukrotność). Napisane wszystko w czystym Ruby.
źródło
Oto moja wersja wydaje mi się jasna, chociaż nie jest tak czysta.
def factorial(num) step = 0 (num - 1).times do (step += 1 ;num *= step) end return num end
To była moja linia testowa IRB, która pokazywała każdy krok.
num = 8;step = 0;(num - 1).times do (step += 1 ;num *= step; puts num) end;num
źródło
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
źródło
I jeszcze inny sposób (=
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)
źródło
Jeszcze tylko jeden sposób, aby to zrobić:
# fact(n) => Computes the Factorial of "n" = n! def fact(n) (1..n).inject(1) {|r,i| r*i }end fact(6) => 720
źródło
Dlaczego biblioteka standardowa wymagałaby metody silniowej, skoro do tego celu służy wbudowany iterator? To się nazywa
upto
.Nie, nie musisz używać rekursji, jak pokazują wszystkie te odpowiedzi.
def fact(n) n == 0 ? 1 : n * fact(n - 1) end
Raczej wbudowany iterator upto może służyć do obliczania silni:
factorial = 1 1.upto(10) {|x| factorial *= x } factorial => 3628800
źródło