Ich werde verrückt: Wo ist die Ruby-Funktion für Fakultät? Nein, ich brauche keine Tutorial-Implementierungen, ich möchte nur die Funktion aus der Bibliothek. Es ist nicht in Mathe!
Ich fange an zu zweifeln, ist es eine Standardbibliotheksfunktion?
@mckeed: Oder (1..6).inject(:*)was etwas prägnanter ist.
sepp2k
8
Warum sollten Sie damit rechnen?
Präsident James K. Polk
4
Ich frage mich, wie der Status der Mathematik- und Naturwissenschaftsbibliotheken für Ruby ist.
Andrew Grimm
5
Nur ein Hinweis zu den bereitgestellten Beispielen mit injizieren. (1..num).inject(:*)schlägt für den Fall fehl, wo num == 0. (1..(num.zero? ? 1 : num)).inject(:*)gibt die richtige Antwort für den Fall 0 und gibt nilfür negative Parameter zurück.
Jogh
Antworten:
135
In der Standardbibliothek gibt es keine Fakultätsfunktion.
Oder geben Sie den Anfangswert direkt an : (1..n).reduce(1, :*).
Andrew Marshall
77
Es ist nicht in der Standardbibliothek enthalten, aber Sie können die Integer-Klasse erweitern.
classIntegerdef factorial_recursive
self<=1?1:self*(self-1).factorial
enddef factorial_iterative
f =1;for i in1..self; f *= i;end; f
endalias:factorial :factorial_iterative
end
NB Iterative Fakultät ist aus offensichtlichen Leistungsgründen eine bessere Wahl.
Was zum Teufel bedeutet das?! Ja, es ist schnell, aber es ist sehr unfreundlich
niccolo m.
3
es ist auch falsch für 0! - sollte so etwas wie sein: wenn self <= 1; 1; sonst; (1..selbst) .reduzieren (: *); Ende
Tarmo
8
@allen - Gib der Sprache keine Schuld, wenn du sie nicht verstehen kannst. Es bedeutet einfach, den Bereich 1 auf sich selbst zu nehmen und dann das erste Element (1) daraus zu entfernen (dh das bedeutet Reduzieren in der funktionalen Programmierung). Entfernen Sie dann das erste Element von dem, was noch übrig ist (2) und multiplizieren Sie diese (: *) miteinander. Entfernen Sie nun das erste Element von den verbleibenden Elementen (3) und multiplizieren Sie es mit der laufenden Summe. Fahren Sie fort, bis nichts mehr übrig ist (dh Sie haben den gesamten Bereich bearbeitet). Wenn Reduzieren fehlschlägt (weil das Array im Fall von 0 leer ist!), Geben Sie trotzdem 1 zurück.
SDJMcHattie
Sie können den Nullfall auch behandeln, indem Sie den Anfangswert in reduce: angeben (1..self).reduce(1,:*).
Mark Thomas
3
Eigentlich können Sie verwenden (2..self).reduce(1,:*), wenn Mikroeffizienz Ihr Ding ist :)
Mark Thomas
14
Sie können auch eine Math.gammaFunktion verwenden, die für ganzzahlige Parameter auf Fakultät hinausläuft.
Aus den Dokumenten: "Beachten Sie, dass Gamma (n) dasselbe ist wie Fakt (n-1) für eine ganze Zahl n> 0. Gamma (n) gibt jedoch float zurück und kann eine Annäherung sein." Wenn man das berücksichtigt, funktioniert es, aber die Reduktionslösung scheint viel einfacher zu sein.
Michael Kohl
Danke dafür! Mein Bauch sagt, dass ich die Standardbibliothek über eine benutzerdefinierte Reduzierung verwenden soll, wann immer dies möglich ist. Die Profilerstellung könnte etwas anderes vorschlagen.
David J.
2
Hinweis: Es ist O (1) und genau für 0..22: MRI Ruby führt tatsächlich eine Suche nach diesen Werten durch (siehe static const double fact_table[]in der Quelle ). Darüber hinaus ist es eine Annäherung. 23! Erfordert beispielsweise eine 56-Bit-Mantisse, die mit dem IEEE 754-Doppel mit 53-Bit-Mantissen nicht genau dargestellt werden kann.
Was ist los mit class Integer ; def ! ; (1..self).inject(:*) ; end ; end?
Aleksei Matiushkin
@mudasobwa Ich mag es, ich habe der Einfachheit halber überarbeitet.
Jasonleonhard
4
Ich würde respektvoll vorschlagen, dass das Überschreiben einer Instanzmethode, die in alle Ruby-Objekte integriert ist, um einen wahrheitsgemäßen Wert anstelle eines falschen Werts zurückzugeben, Sie möglicherweise nicht zu vielen Freunden macht.
MatzFan
Es kann sehr gefährlich sein, den Negationsoperator zu etwas anderem zu machen, wenn adies Integerder Fall ist. !aAndernfalls kann ein Fehler auftreten, der sehr schwer zu erkennen ist. Wenn es sich azufällig um eine große Zahl 357264543handelt,
gerät
Diese Antwort war eher eine coole Sache als ein praktisches Beispiel.
Die Verwendung Math.gamma.floorist eine einfache Möglichkeit, eine Näherung zu erstellen und diese dann wieder auf das richtige ganzzahlige Ergebnis abzurunden. Sollte für alle Ganzzahlen funktionieren, fügen Sie gegebenenfalls eine Eingabeprüfung hinzu.
Korrektur: Nachdem n = 22es aufgehört hat, eine genaue Antwort zu geben und Annäherungen erzeugt.
Ayarch
2
Mit großem Respekt für alle, die teilgenommen haben und ihre Zeit damit verbracht haben, uns zu helfen, möchte ich meine Benchmarks für die hier aufgeführten Lösungen teilen. Parameter:
Iterationen = 1000
n = 6
user system total real
Math.gamma(n+1)0.0003830.0001060.000489(0.000487)(1..n).inject(:*)||10.0039860.0000000.003986(0.003987)(1..n).reduce(1,:*)0.0039260.0000000.003926(0.004023)1.upto(n){|x| factorial *= x }0.0037480.0117340.015482(0.022795)
Für n = 10
user system total real
0.0003780.0001020.000480(0.000477)0.0044690.0000070.004476(0.004491)0.0045320.0000240.004556(0.005119)0.0277200.0112110.038931(0.058309)
Es ist erwähnenswert, dass der schnellste Math.gamma(n+1)auch nur ungefähr für n> 22 ist und daher möglicherweise nicht für alle Anwendungsfälle geeignet ist.
Neil Slater
1
Nur ein anderer Weg, obwohl es wirklich nicht notwendig ist.
classFactorial
attr_reader :num
def initialize(num)@num= num
enddef find_factorial
(1..num).inject(:*)||1endend
number =Factorial.new(8).find_factorial
puts number
Sie werden wahrscheinlich eine Ruby- Funktionsanforderung nützlich finden. Es enthält einen nicht trivialen Patch , der ein Demo-Bash-Skript enthält . Der Geschwindigkeitsunterschied zwischen einer naiven Schleife und der in der Charge dargestellten Lösung kann buchstäblich 100x (hundertfach) betragen. Geschrieben alles in reinem Rubin.
classIntegerdef factorial
returnself<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
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)
Warum sollte die Standardbibliothek eine faktorielle Methode erfordern, wenn es genau für diesen Zweck einen integrierten Iterator gibt? Es wird genanntupto .
Nein, Sie müssen keine Rekursion verwenden, wie all diese anderen Antworten zeigen.
def fact(n)
n ==0?1: n * fact(n -1)end
Vielmehr kann der eingebaute Iterator bis zu verwendet werden, um Fakultäten zu berechnen:
factorial =11.upto(10){|x| factorial *= x }
factorial
=>3628800
6.downto(1).inject(:*)
(1..6).inject(:*)
was etwas prägnanter ist.(1..num).inject(:*)
schlägt für den Fall fehl, wonum == 0
.(1..(num.zero? ? 1 : num)).inject(:*)
gibt die richtige Antwort für den Fall 0 und gibtnil
für negative Parameter zurück.Antworten:
In der Standardbibliothek gibt es keine Fakultätsfunktion.
quelle
Math.gamma
Methode, zB stackoverflow.com/a/37352690/407213So ist das besser
quelle
(1..n).reduce(1, :*)
.Es ist nicht in der Standardbibliothek enthalten, aber Sie können die Integer-Klasse erweitern.
NB Iterative Fakultät ist aus offensichtlichen Leistungsgründen eine bessere Wahl.
quelle
Schamlos von http://rosettacode.org/wiki/Factorial#Ruby abgeschnitten , ist mein persönlicher Favorit
Diese Implementierung ist auch die schnellste unter den in Rosetta Code aufgeführten Varianten.
Update Nr. 1
Hinzugefügt
|| 1
, um den Nullfall zu behandeln.Update Nr. 2
Mit Dank und Anerkennung an Mark Thomas ist hier eine Version, die etwas effizienter, eleganter und dunkler ist:
quelle
reduce
: angeben(1..self).reduce(1,:*)
.(2..self).reduce(1,:*)
, wenn Mikroeffizienz Ihr Ding ist :)Sie können auch eine
Math.gamma
Funktion verwenden, die für ganzzahlige Parameter auf Fakultät hinausläuft.quelle
0..22
: MRI Ruby führt tatsächlich eine Suche nach diesen Werten durch (siehestatic const double fact_table[]
in der Quelle ). Darüber hinaus ist es eine Annäherung. 23! Erfordert beispielsweise eine 56-Bit-Mantisse, die mit dem IEEE 754-Doppel mit 53-Bit-Mantissen nicht genau dargestellt werden kann.In Mathe
factorial of n
ist nur diegamma function of n+1
(siehe: http://en.wikipedia.org/wiki/Gamma_function )
Ruby hat es
Math.gamma()
also einfach benutztMath.gamma(n+1)
und auf Wunsch auf eine ganze Zahl zurückgesetzt.quelle
Beispiele
quelle
class Integer ; def ! ; (1..self).inject(:*) ; end ; end
?a
diesInteger
der Fall ist.!a
Andernfalls kann ein Fehler auftreten, der sehr schwer zu erkennen ist. Wenn es sicha
zufällig um eine große Zahl357264543
handelt,Ich würde es tun
quelle
Ich habe gerade mein eigenes geschrieben:
Sie können auch eine fallende Fakultät definieren:
quelle
Rufen Sie einfach diese Funktion auf
Beispiele
quelle
Die Verwendung
Math.gamma.floor
ist eine einfache Möglichkeit, eine Näherung zu erstellen und diese dann wieder auf das richtige ganzzahlige Ergebnis abzurunden. Sollte für alle Ganzzahlen funktionieren, fügen Sie gegebenenfalls eine Eingabeprüfung hinzu.quelle
n = 22
es aufgehört hat, eine genaue Antwort zu geben und Annäherungen erzeugt.Mit großem Respekt für alle, die teilgenommen haben und ihre Zeit damit verbracht haben, uns zu helfen, möchte ich meine Benchmarks für die hier aufgeführten Lösungen teilen. Parameter:
Iterationen = 1000
n = 6
Für n = 10
quelle
Math.gamma(n+1)
auch nur ungefähr für n> 22 ist und daher möglicherweise nicht für alle Anwendungsfälle geeignet ist.Nur ein anderer Weg, obwohl es wirklich nicht notwendig ist.
quelle
Sie werden wahrscheinlich eine Ruby- Funktionsanforderung nützlich finden. Es enthält einen nicht trivialen Patch , der ein Demo-Bash-Skript enthält . Der Geschwindigkeitsunterschied zwischen einer naiven Schleife und der in der Charge dargestellten Lösung kann buchstäblich 100x (hundertfach) betragen. Geschrieben alles in reinem Rubin.
quelle
Hier scheint mir meine Version klar zu sein, obwohl sie nicht so sauber ist.
Dies war meine irb-Testlinie, die jeden Schritt zeigte.
quelle
quelle
Und noch ein anderer Weg (=
quelle
Nur noch eine Möglichkeit:
quelle
Warum sollte die Standardbibliothek eine faktorielle Methode erfordern, wenn es genau für diesen Zweck einen integrierten Iterator gibt? Es wird genannt
upto
.Nein, Sie müssen keine Rekursion verwenden, wie all diese anderen Antworten zeigen.
Vielmehr kann der eingebaute Iterator bis zu verwendet werden, um Fakultäten zu berechnen:
quelle