Fakultät reelle Zahlen

Hey Leute.
Ich suche nach einer formel für die fakultätsfunktion.
Die fakultät von reelen zahlen ist ja die gamma funktion oder so,
bzw irgendwas mit integral. das hat ich leider nicht in der schule und
versteh das nicht ^^
Hier ist etwas was ich gefunden hab: link
Naja. Das würd ich gern nachprogrammieren… aber wie genau ist jetzt f(x) definiert?

Sehe ich das richtig, dass du nicht weisst was ein Integral ist?

Eine Möglichkeit Integrale zu berechnen ist eine einfache Schleife, sofern man die Funktion nicht Integrieren kann oder will.

Die Fakultätsfunktion als Integral ist eigentlich ein Trick um keine Schleifen für die Berechnung verwenden zu müssen. Das führt das ganze etwa ad absurdum.

ähm ja… bin zwar in der Q1, aber das war noch nicht dran…
ich habs mir mal versuhct anzuschauen, aber es scheint kompliziert zu sein…
haben integrale nicht etwas mit „irgendwas läuft gegen etwas“ zu tun? Ich hab keine ahnung ^^

ja und… wie könnte man das nun implementieren? ^^
sorry aber ich komm nicht drauf :frowning:

Ähm, ja, die Fakultät ist da Produkt aller Zahlen von 1 bis n.

Also die einfachste Schleife überhaupt. 4! = 1•2•3•4

Also, wenn du wirklich nur Fakultät berechnen willst, warum dann nicht mit einer Schleife? Einfach i von 2 bis n durchschleifen lassen und den Wert (am Anfang 1) mit i multiplizieren.
Und keine Ahnung, ob du die Funktion öfter brauchst, aber eventuell als Methode auslagern und dann immer nur n dorthin übergeben. Dann bekommst du bequem deinen Fakultätswert zurück.

Wenn du das wirklich brauchst, dann verwende z.B. https://commons.apache.org/ (verwendet http://en.wikipedia.org/wiki/Lanczos_approximation)

Egal ob nur einmal oder mehrfach aufgerufen - das gehört auf jeden Fall in eine Methode!

Die Fakultät ist nur auf den natürlichen Zahlen definiert. Wozu sollte man das also auf ein Integral zurückführen? Die Diskretheit ist doch gerade eine der schönen Eigenschaften der Fakultät.
Wenn eine näherungsweise Berechnung für große Fakultäten ausreicht, dann wäre die Stirlingformel eine Option. Denn Potenzen lassen sich deutlich effizienter berechnen als Fakultäten (z. B. durch Zerlegen des Exponenten).

Theoretisch ja, aber wenn ich was wirklich nur 1x brauche, lass ich es da, wo’s ist. Für mich selbst persönlich und ganz auf eigene Gefahr ist das dann übersichtlicher. :slight_smile:

Das solltest du dir aber selbst im allerkleinsten Sil abgewöhnen. Nach dem schreiben des eigentlichen Codes sollte immer eine Refactoring-Phase kommen.
Konkretes Beispiel (mit IntelliJ IDEA Shortcuts):

    public static void main(String[] args) {
        long fakultaet = 1;
        for (int i = 1; i <= 12; i++)
            fakultaet *= i;
        System.out.println("Die Fakultät von 12 ist " + fakultaet);
    }
}```
Die möglichen Codeverbesserungen fallen sofort auf. Zuerst sollte man die 12 aus der Berechnung holen. (Den Cursor auf die 12 setzen, dann Strg+Alt+V und der 12 den Namen `n` geben, dann die `int n = 12;` Zeile hochschieben (Strg+Shift+Pfeil-Hoch))):
```public static void main(String[] args) {
    int n = 12;
    long fakultaet = 1;
    for (int i = 1; i <= n; i++)
        fakultaet *= i;
    System.out.println("Die Fakultät von 12 ist " + fakultaet);
}```
Danach die Methode extrahieren (Zeilen 3-5 markieren, Strg+Alt+M, Methodennamen vergeben):
```public class Foobar {
    public static void main(String[] args) {
        int n = 12;
        long fakultaet = fakultaet(n);
        System.out.println("Die Fakultät von 12 ist " + fakultaet);
    }

    private static long fakultaet(int n) {
        long fakultaet = 1;
        for (int i = 1; i <= n; i++)
            fakultaet *= i;
        
        return fakultaet;
    }
}```
Dann kann man noch das `n` und `fakultaet` inlinen (jeweils über den Variablennamen gehen, Strg+Alt+N, bestätigen), sodass die Main so aussieht:
```public static void main(String[] args) {
    System.out.println("Die Fakultät von 12 ist " + fakultaet(12));
}```

Das dauert keine 2 Minuten und man hat einen vernünftig lesbaren Code, dessen Fakultätsfunktion man dann ggf. sogar in eine andere Klasse auslagern könnte (Textcursor über Methodennamen, F6 drücken).

Wenn ich die Main-Methoden vergleiche, dann finde ich ```public static void main(String[] args) {
    System.out.println("Die Fakultät von 12 ist " + fakultaet(12));
}```
deutlich lesbarer als ```public static void main(String[] args) {
    long fakultaet = 1;
    for (int i = 1; i <= 12; i++)
        fakultaet *= i;
    System.out.println("Die Fakultät von 12 ist " + fakultaet);
}```

Nagut, ich seh’s. Ich werd’s mir mal versuchen anzugewöhnen.

Nebenbei: eine Funktion ohne Seiteneffekte, die nur 20 mögliche Argumente erlaubt, würde ich cachen

 private static long[] fakultaet = 
        {       
                1,                                            
                1,
                2,
                6,
                24,
                120,
                720,
                5040,
                40320,
                362880,
                3628800,
                39916800,
                479001600,
                6227020800L,
                87178291200L,
                1307674368000L,
                20922789888000L,
                355687428096000L,
                6402373705728000L,
                121645100408832000L,
                2432902008176640000L // Ende bei 20!
        };

hat noch dazu den Vorteil, dass kein ‘stiller’ Überlauf stattfindet und dass negative Argumente gleich einen Fehler werfen.

nicht dass es nicht völlig auszuschließen wäre :wink: ,
aber muss man in einem Thread von mymaksimus mit über 800 Beiträgen wirklich ab #4 von der Fingerübung der ersten Stunde Java-Unterricht sprechen?

zumal es am Anfang (wenn auch schon nicht intelligenterweise im Thread-Titel deutlich gemacht) etwas anders klingt:

usw.

ich bin übrigens mal froh dass das nicht in Java-Grundlagen-Area steht,
falls es wirklich um reelle Zahlen geht, und nicht nicht die Dummy-Schleife

Vielleicht sollte man erstmal klären, ob es nun um die Fakultät geht, oder um die http://mathworld.wolfram.com/GammaFunction.html

Aehm… naja… leute…

Wie man eine schleife zur berechnung der fakultaet von x wobei x eine ganze zahl iat schreibt…

Weiss ich bereits, danke slaterB! :smiley:

Tut mir wirklich leid, ich hab mich echt schlecht ausgedrückt ^^ es ging mir tatsaechlich um alle reelen zahlen, also auch kommazahlen, wobei das rein mathematisch ja nicht moeglich ist - mit dieser gamma funktion aber anscheinen irgendwie doch…

Ich will diese Kurve hinbekommen wie sie auf dem bild welches sich auf der seite befindet welche ich verlinkt hatte hinbekommen…

:smiley:

#groessterausdrucksfaileversorrydafür ^^

Gut, sollte es wirklich um Fakultät gehen wundert mich erlich gesagt das die rekursive Variante noch nicht kam :

{
	if(i.compareTo(BigInteger.ONE)<0)
		throw new IllegalArgumentException("i must grater than 0");
	if(i.compareTo(BigInteger.ONE)==0)
		return BigInteger.ONE; //wobei hier auch "return i;" gehen würde da beides "1" ist
	return BigInteger.multiply(i.substract(BigInteger.ONE));
}```
Fakultät ist relativ einfach erklärt : das Produkt von 1 bis n inklusive. Also wie schon gezeigt : 4! = 1 x 2 x 3 x 4 = 24

Zur Erklärung was der Code macht falls du noch nicht mit BigInteger und Comparable gearbeitet hast :

BigInteger ist eine art Wraper-Klasse für ints, als ganze Zahlen. Man verwendet BigInteger wenn der Wertebereich von int und long zu klein sind. BigInteger kennt in dem sinne keine begrenzung.
Comparable ist ein Vergleichs-Interface mit der Methode compareTo(T) und ist auch relativ klar definiert :

gegeben sei x.compareTo(y)

Wenn x kleiner als y ist wird -1 geliefert.
Wenn x gleich y ist wird 0 geliefert.
wenn x größer als y ist wird 1 geliefert.

Zum Code :

Zu erst wird überprüft über denn der Wert des übergebenen Objektes größer als 0 ist. Dazu wird i mit "1" verglichen. Wenn i kleiner als "1" ist dann wird -1 geliefert und das if ist true > es fliegt eine Exception die darauf hinweist das i mindestens "1" oder größer sein muss.
Dann wird überprüft ob i denn genau den Wert "1" hat. Das ist die Abbruchbedingung bei der die Rekursion abbricht und wieder "rückwärts nach oben läuft".
Und letzten Endes kommt eben die eigentliche Funktion : n! = n x (n-1).

Ich hab mich jetzt mal bewusst für BigInteger entschieden da wie schon gezeigt wurde auch Long recht schnell am Ende ist.



--- EDIT ---
ok, geht doch um Gamma-Funktion ... vergiss den Schrott hier
(@SlaterB : bitte mal Titel korrigieren)

Na ja, es geht hier doch eindeutig um die Gamma-Funktion (die - ganz nebenbei - die Fakultät interpoliert).

Für einen gegebenen rellen Input $x>0$ den Wert $Gamma(x)$ mit Java (oder einer anderen Programmiersprache, mit genügend großer Genauigkeit) zu berechnen ist nicht trivial und ohne
tiefere mathematische Kenntnisse wohl kaum zu bewerkstelligen.

In so einem Fall verwendet man am besten eine Bibliothek: http://commons.apache.org/proper/commons-math/userguide/special.html

Wie ich oben ja schon geschrieben habe, gibt es die Fakultät nur auf natürlichen Zahlen. Die Gammafunktion ist eine Erweiterung der Fakultät auf die komplexen Zahlen.
Je nachdem, was du benötigst, reicht die Stirlingformel (siehe #7, ist wahrscheinlich untergegangen) als Näherung ggf. aus.

Was möchtest du denn genau machen? Wofür brauchst du eine Erweiterung der Fakultät?

Zum Thema Fakultät kann ich nur http://www.luschny.de/math/factorial/FastFactorialFunctions.htm empfehlen.

Auf der Seite findet man auch Alternativen zur Gamma-Funktion: http://www.luschny.de/math/factorial/hadamard/HadamardsGammaFunction.html

Es ist keineswegs so, dass ich auch nur ein bisschen davon verstehen würde, wie das genau geht (Landei erinnert sich evtl. das hatten wir ja schon im alten Forum), aber ich verwende folgendes:


import static java.lang.Math.*;

public class MoreMath {
	private static final double INV_GAMMA1P_M1_A0 = .611609510448141581788E-08;
	private static final double INV_GAMMA1P_M1_A1 = .624730830116465516210E-08;
	private static final double INV_GAMMA1P_M1_B1 = .203610414066806987300E+00;
	private static final double INV_GAMMA1P_M1_B2 = .266205348428949217746E-01;
	private static final double INV_GAMMA1P_M1_B3 = .493944979382446875238E-03;
	private static final double INV_GAMMA1P_M1_B4 = -.851419432440314906588E-05;
	private static final double INV_GAMMA1P_M1_B5 = -.643045481779353022248E-05;
	private static final double INV_GAMMA1P_M1_B6 = .992641840672773722196E-06;
	private static final double INV_GAMMA1P_M1_B7 = -.607761895722825260739E-07;
	private static final double INV_GAMMA1P_M1_B8 = .195755836614639731882E-09;
	private static final double INV_GAMMA1P_M1_P0 = .6116095104481415817861E-08;
	private static final double INV_GAMMA1P_M1_P1 = .6871674113067198736152E-08;
	private static final double INV_GAMMA1P_M1_P2 = .6820161668496170657918E-09;
	private static final double INV_GAMMA1P_M1_P3 = .4686843322948848031080E-10;
	private static final double INV_GAMMA1P_M1_P4 = .1572833027710446286995E-11;
	private static final double INV_GAMMA1P_M1_P5 = -.1249441572276366213222E-12;
	private static final double INV_GAMMA1P_M1_P6 = .4343529937408594255178E-14;
	private static final double INV_GAMMA1P_M1_Q1 = .3056961078365221025009E+00;
	private static final double INV_GAMMA1P_M1_Q2 = .5464213086042296536016E-01;
	private static final double INV_GAMMA1P_M1_Q3 = .4956830093825887312020E-02;
	private static final double INV_GAMMA1P_M1_Q4 = .2692369466186361192876E-03;
	private static final double INV_GAMMA1P_M1_C = -.422784335098467139393487909917598E+00;
	private static final double INV_GAMMA1P_M1_C0 = .577215664901532860606512090082402E+00;
	private static final double INV_GAMMA1P_M1_C1 = -.655878071520253881077019515145390E+00;
	private static final double INV_GAMMA1P_M1_C2 = -.420026350340952355290039348754298E-01;
	private static final double INV_GAMMA1P_M1_C3 = .166538611382291489501700795102105E+00;
	private static final double INV_GAMMA1P_M1_C4 = -.421977345555443367482083012891874E-01;
	private static final double INV_GAMMA1P_M1_C5 = -.962197152787697356211492167234820E-02;
	private static final double INV_GAMMA1P_M1_C6 = .721894324666309954239501034044657E-02;
	private static final double INV_GAMMA1P_M1_C7 = -.116516759185906511211397108401839E-02;
	private static final double INV_GAMMA1P_M1_C8 = -.215241674114950972815729963053648E-03;
	private static final double INV_GAMMA1P_M1_C9 = .128050282388116186153198626328164E-03;
	private static final double INV_GAMMA1P_M1_C10 = -.201348547807882386556893914210218E-04;
	private static final double INV_GAMMA1P_M1_C11 = -.125049348214267065734535947383309E-05;
	private static final double INV_GAMMA1P_M1_C12 = .113302723198169588237412962033074E-05;
	private static final double INV_GAMMA1P_M1_C13 = -.205633841697760710345015413002057E-06;
	private static final double LANCZOS_G = 607.0 / 128.0;
	private static final double SQRT_TWO_PI = sqrt(java.lang.StrictMath.PI * 2.0);

	private static final double[] LANCZOS = { 0.99999999999999709182,
			57.156235665862923517, -59.597960355475491248,
			14.136097974741747174, -0.49191381609762019978,
			.33994649984811888699e-4, .46523628927048575665e-4,
			-.98374475304879564677e-4, .15808870322491248884e-3,
			-.21026444172410488319e-3, .21743961811521264320e-3,
			-.16431810653676389022e-3, .84418223983852743293e-4,
			-.26190838401581408670e-4, .36899182659531622704e-5, };

	/**
	 * Aufgrund der Genauigkeit von double liefert die Gammafunktion fuer
	 * alle Werte zwischen GAMMA_ENTRY_MIN und GAMMA_LEAVE_MIN die selben
	 * Werte. Der tatsaechliche Wert fuer GAMMA_LOCAL_MIN wurde mit einer
	 * hoeheren Aufloesung berechnet.
	 */
	public static final double GAMMA_ENTRY_MIN = 1.4616321274583250;
	public static final double GAMMA_LOCAL_MIN = 1.4616321449683624;
	public static final double GAMMA_LEAVE_MIN = 1.4616321614601254;

	private MoreMath() {
	}

	/**
	 * Returns the faculty of value a.
	 * 
	 * @param value
	 * @return faculty
	 */
	public static double faculty(double value) {
		return gamma(value + 1.0);
	}

	/**
	 * Returns the gamma of value a.
	 * 
	 * @param value
	 * @return gamma
	 */
	public static double gamma(double value) {
		if ((value == rint(value)) && (value <= 0.0)) {
			return Double.NaN;
		}
		final double ret;
		final double absX = abs(value);
		if (absX <= 20.0) {
			if (value >= 1.0) {
				double prod = 1.0;
				double t = value;
				while (t > 2.5) {
					t -= 1.0;
					prod *= t;
				}
				t -= 1.0;
				if (t < -0.5 || t > 1.5) {
					throw new ArithmeticException("can't compute gamma for "
							+ value);
				}
				ret = prod / (1.0 + invGamma1pm1(t));
			} else {
				double prod = value;
				double t = value;
				while (t < -0.5) {
					t += 1.0;
					prod *= t;
				}
				if (t < -0.5 || t > 1.5) {
					throw new ArithmeticException("can't compute gamma for "
							+ value);
				}
				ret = 1.0 / (prod * (1.0 + invGamma1pm1(t)));
			}
		} else {
			final double y = absX + LANCZOS_G + 0.5;
			final double gammaAbs = SQRT_TWO_PI / value * pow(y, absX + 0.5)
					* exp(-y) * lanczos(absX);
			if (value > 0.0) {
				ret = gammaAbs;
			} else {
				ret = -PI / (value * sin(PI * value) * gammaAbs);
			}
		}
		return ret;
	}

	public static double lanczos(double value) {
		double sum = 0.0;
		for (int i = LANCZOS.length - 1; i > 0; --i) {
			sum += LANCZOS** / (value + i);
		}
		return sum + LANCZOS[0];
	}

	private static double invGamma1pm1(double x) {
		if (x < -0.5) {
			throw new ArithmeticException("value too small (<-0.5) " + x);
		}
		if (x > 1.5) {
			throw new ArithmeticException("value too large (>1.5) " + x);
		}
		final double ret;
		final double t = x <= 0.5 ? x : (x - 0.5) - 0.5;
		if (t < 0.0) {
			final double a = INV_GAMMA1P_M1_A0 + t * INV_GAMMA1P_M1_A1;
			double b = INV_GAMMA1P_M1_B8;
			b = INV_GAMMA1P_M1_B7 + t * b;
			b = INV_GAMMA1P_M1_B6 + t * b;
			b = INV_GAMMA1P_M1_B5 + t * b;
			b = INV_GAMMA1P_M1_B4 + t * b;
			b = INV_GAMMA1P_M1_B3 + t * b;
			b = INV_GAMMA1P_M1_B2 + t * b;
			b = INV_GAMMA1P_M1_B1 + t * b;
			b = 1.0 + t * b;
			double c = INV_GAMMA1P_M1_C13 + t * (a / b);
			c = INV_GAMMA1P_M1_C12 + t * c;
			c = INV_GAMMA1P_M1_C11 + t * c;
			c = INV_GAMMA1P_M1_C10 + t * c;
			c = INV_GAMMA1P_M1_C9 + t * c;
			c = INV_GAMMA1P_M1_C8 + t * c;
			c = INV_GAMMA1P_M1_C7 + t * c;
			c = INV_GAMMA1P_M1_C6 + t * c;
			c = INV_GAMMA1P_M1_C5 + t * c;
			c = INV_GAMMA1P_M1_C4 + t * c;
			c = INV_GAMMA1P_M1_C3 + t * c;
			c = INV_GAMMA1P_M1_C2 + t * c;
			c = INV_GAMMA1P_M1_C1 + t * c;
			c = INV_GAMMA1P_M1_C + t * c;
			if (x > 0.5) {
				ret = t * c / x;
			} else {
				ret = x * ((c + 0.5) + 0.5);
			}
		} else {
			double p = INV_GAMMA1P_M1_P6;
			p = INV_GAMMA1P_M1_P5 + t * p;
			p = INV_GAMMA1P_M1_P4 + t * p;
			p = INV_GAMMA1P_M1_P3 + t * p;
			p = INV_GAMMA1P_M1_P2 + t * p;
			p = INV_GAMMA1P_M1_P1 + t * p;
			p = INV_GAMMA1P_M1_P0 + t * p;
			double q = INV_GAMMA1P_M1_Q4;
			q = INV_GAMMA1P_M1_Q3 + t * q;
			q = INV_GAMMA1P_M1_Q2 + t * q;
			q = INV_GAMMA1P_M1_Q1 + t * q;
			q = 1.0 + t * q;
			double c = INV_GAMMA1P_M1_C13 + (p / q) * t;
			c = INV_GAMMA1P_M1_C12 + t * c;
			c = INV_GAMMA1P_M1_C11 + t * c;
			c = INV_GAMMA1P_M1_C10 + t * c;
			c = INV_GAMMA1P_M1_C9 + t * c;
			c = INV_GAMMA1P_M1_C8 + t * c;
			c = INV_GAMMA1P_M1_C7 + t * c;
			c = INV_GAMMA1P_M1_C6 + t * c;
			c = INV_GAMMA1P_M1_C5 + t * c;
			c = INV_GAMMA1P_M1_C4 + t * c;
			c = INV_GAMMA1P_M1_C3 + t * c;
			c = INV_GAMMA1P_M1_C2 + t * c;
			c = INV_GAMMA1P_M1_C1 + t * c;
			c = INV_GAMMA1P_M1_C0 + t * c;
			if (x > 0.5) {
				ret = (t / x) * ((c - 0.5) - 0.5);
			} else {
				ret = x * c;
			}
		}
		return ret;
	}
}```
Dem Variablennamen Lanczos nach zu Urteilen, dürfte das die oben erwähnte Lanczos-Approximation sein, aber ich steige nicht ein bisschen dahinter, wie sie funktioniert. :(
Darüber hinaus ist diese Implementation auch nur für positive Zahlen > 0 gedacht.

[quote=Bleiglanz]Für einen gegebenen rellen Input $x>0$ den Wert $Gamma(x)$ mit Java (oder einer anderen Programmiersprache, mit genügend großer Genauigkeit) zu berechnen ist nicht trivial und ohne
tiefere mathematische Kenntnisse wohl kaum zu bewerkstelligen.[/quote]

der grund… weshalb ich mich an die profis hier wende :smiley:

*** Edit ***

naja mathematische kenntnisse sind bei mir ja auch nicht vorhanden…
was ich hinbekommen will, da anscheinend keiner den link anklickt, ist das hier:

*** Edit ***

ich merk grad… das ist ja die gamma funktion… ja geile schei**e… ^^