# Probleme beim Rechnen mit BigDecimal



## hdi (29. Aug 2009)

Hi,

ich möchte ein paar Wahrscheinlichkeiten ausrechnen, und habe versucht eine mathematische Formel zu implementieren:





Es geht hier um die Wahrscheinlichkeit eines gewissen Würfelergebnisses.
In dem obigen Bsp ist das die Formel für 6 Treffer einer Zahl bei 10 Würfen.

Aber irgendwas läuft da total schief. Anfangs _scheint_ noch alles zu stimmen (ist ja nicht wirklich möglich die Ergebnisse auf Richtigkeit abzuschätzen bei sowas).

Hier mal ein Auszug:


```
1 mal die gleiche Zahl bei 1 Würfeln: 16.67 %
1 mal die gleiche Zahl bei 2 Würfeln: 30.56 %
1 mal die gleiche Zahl bei 3 Würfeln: 42.13 %
1 mal die gleiche Zahl bei 4 Würfeln: 51.77 %
1 mal die gleiche Zahl bei 5 Würfeln: 59.81 %
1 mal die gleiche Zahl bei 6 Würfeln: 66.51 %
1 mal die gleiche Zahl bei 7 Würfeln: 72.09 %
1 mal die gleiche Zahl bei 8 Würfeln: 76.74 %
1 mal die gleiche Zahl bei 9 Würfeln: 80.62 %
1 mal die gleiche Zahl bei 10 Würfeln: 83.85 %
1 mal die gleiche Zahl bei 11 Würfeln: 86.54 %
1 mal die gleiche Zahl bei 12 Würfeln: 88.78 %
[COLOR="Red"]1 mal die gleiche Zahl bei 13 Würfeln: 28.13 %
1 mal die gleiche Zahl bei 14 Würfeln: 2.06 %
1 mal die gleiche Zahl bei 15 Würfeln: 2.24 %[/COLOR]
```

Also 16% (= 1/6) bei einem Wurf stimmt ja eindeutig, und es scheint zumindest
einigermaßen sinnig wie die Werte sich verhalten, bis es zu Würfen >= 13 kommt.
Die Wahrscheinlichkeit für einen Treffer bei 13 Würfen kann ja nicht 80% geringer sein als die für 12 Würfe.

Ich bitte euch deshalb mal, meinen Code anzukucken, ich habe mit BigDecimal noch nie etwas gemacht, und generell nicht so die Erfahrung mit Kalkulationen dieser Größenordnung beim Programmieren. Wer weiss was da alles schief laufen kann.

Ich danke!


```
public class Wuerfel {

	public static void main(String[] args) {

		// w = Anzahl Würfel, also ganz einfach Anzahl der Würfe
		for (int w = 1; w <= 15; w++) {

			// Verlangte Anzahl an Treffern einer Zahl:
			// (welche ist ja egal, sind ja alle gleich wahrscheinlich)
			int t = 1;

			// Dies wird die Wahrscheinlichkeit für t Treffer aus w Würfen:
			BigDecimal p = new BigDecimal(0);

			// Laut Formel wird, von der Anzahl der verlangten Treffer
			// beginnend, eine Summe
			// gebildet (bis Summen-Index == Anzahl Würfel)

			for (int s = t; s <= w; s++) {
				// 1/6:
				BigDecimal einSechstel = new BigDecimal(divide(
						new BigDecimal(1.0), new BigDecimal(6.0)).doubleValue());
				// 1 - 1/6:
				BigDecimal einsMinusEinSechstel = new BigDecimal(1.0)
						.subtract(einSechstel);
				// Die Wahrscheinlichkeit für diesen Durchgang der Summe:
				// Es werden einige eigene Funktionen aufgerufen, siehe unten.
				BigDecimal chance = (ueber(w, s).multiply(einSechstel.pow(s))
						.multiply(einsMinusEinSechstel.pow(w - s)));
				// Wir addieren die Wahrscheinlichkeit für diesen Durchlauf zu
				// der Gesamt-Wahrscheinlichkeit
				p = p.add(chance);
			}
			// Wenn wir hier ankommen, wurde "p" (w-s) mal aufaddiert, und darin
			// sollte nun
			// die Gesamt-Wahrscheinlichkeit stehen:
			System.out.println(t + " mal die gleiche Zahl bei " + w
					+ " Würfeln: " + toPerc(p));

		}

	}

	// Berechnet "oben über unten":
	private static BigDecimal ueber(int oben, int unten) {
		BigDecimal fakOben = new BigDecimal(fak(oben)); // oben!
		BigDecimal fakUnten = new BigDecimal(fak(unten)); // unten!
		BigDecimal fakObenMinusUnten = new BigDecimal(fak(oben - unten)); // (oben-unten)!

		// (oben!) / ((unten!) * (oben-unten)!)
		BigDecimal ret = new BigDecimal(divide(fakOben,
				fakUnten.multiply(fakObenMinusUnten)).doubleValue());
		return ret;
	}

	// Berechnet die Fakultät z!
	private static int fak(int z) {
		if (z == 0 || z == 1) {
			return 1;
		}
		int fak = z;
		for (int prev = (z - 1); prev > 1; prev--) {
			fak *= prev;
		}
		return fak;
	}

	// wandelt eine Zahl in Prozent um, zB 0.5 -> 50 %
	private static String toPerc(BigDecimal d) {
		d = d.multiply(new BigDecimal(100));
		return new DecimalFormat("#.##").format(d) + " %";
	}

	// eigene Divide Methode, bei der ein Scale angegeben ist, sonst kann es zu
	// Brüchen
	// mit unendlichen Nachkommastellen kommen (zB 1/3), was zu einer Exception
	// führt.
	private static BigDecimal divide(BigDecimal v1, BigDecimal v2) {
		BigDecimal ret = v1.divide(v2, 10, RoundingMode.HALF_UP);
		return ret;
	}
}
```

*PS: Die Formel hab ich aus einem Mathe-Forum, ich gehe stark davon aus dass die also stimmt!*


----------



## SlaterB (30. Aug 2009)

1800 Postings und keine Idee das selber herauszufinden, Zwischenwerte anschauen?
wenn du das hier nicht übst, wie soll das bei richtigen Problemen klappen?

Tipp um die Menge der Berechnungen zu reduzieren:
berechne nur
for (int s = t; s <= 1; s++) {


--------

hier noch ein richtiger Tipp:


```
static final DecimalFormat PERCENT_FORMAT = new DecimalFormat("#.##%");
	// wandelt eine Zahl in Prozent um, zB 0.5 -> 50 %
	private static String toPerc(BigDecimal d) {
		return PERCENT_FORMAT.format(d);
	}

	static final BigDecimal einSechstel = divide(BigDecimal.ONE, new BigDecimal("6"));
	static final BigDecimal einsMinusEinSechstel = BigDecimal.ONE.subtract(einSechstel);
```


----

wieso rechnest du
new BigDecimal(divide().doubleValue());

divide() liefert doch schon einen BigDecimal?

-------
unabhängig davon besser nie new BigDecimal(double) verwenden, teste

		System.out.println(new BigDecimal(2.3));
		System.out.println(BigDecimal.valueOf(2.3));
		System.out.println(new BigDecimal("2.3"));


----------



## Painii (30. Aug 2009)

Du rechnest in fak() mit primitivem int -> bei 13! war da glaub ich irgendwann Schluss (Überlauf).


----------



## SlaterB (30. Aug 2009)

macht das jetzt Sinn, meine pädagogischen 'bitte selber herausfinden'-Ratschläge ad absurdum zu führen?


----------



## Painii (30. Aug 2009)

Ich seh das ganze grade mal als einen Fall von "betriebsblind" an, ich hatte auch schon solche Tage...

Mir hat es in dem Fall (Implementierung der Fakultät) auch nicht geholfen zu sagen "such mal selber", sondern dass mir jemand gesagt hat "da ist der Fehler"...
Und weil mir das suchen da selbst nichts gebracht hat ausser Frust (ich hab irgendwo Fehler gesucht und Stunden das Programm umgeschrieben) will ich das nicht anderen auch antun.


----------



## hdi (30. Aug 2009)

Hey Leute, danke für die Hilfe. Lag wohl wirklich am int der Fakultät. Hatte das eig. mal gegen long ausgetauscht (jetzt BigInteger, nur um sicher zu sein), aber zu dem Zeitpunkt war wohl noch woanders ein Fehler drinnen.

@SlaterB: Das Problem war, dass ich nie zu 100% wusste, ob es nun zu Rechenfehlern kommt oder ob ich die Formel falsch implementiert habe (rein sinngemäß). Zustäzlich kann man die Ergebnisse nicht wirklich nachrechnen (dauert per Hand einfach zu lange) oder abschätzen.
Ich saß ungelogen seit über 5 Stunden an diesem Mist, und ich habe noch nie mit solchen Werten gerechnet. Ich hatte einfach sowas von keinen Bock mehr :bae:


----------

