Random: Ungleiche Verteilung abhängig von if-Anweisung?

Hallo,

ich bin gerade auf ein für mich nicht nachvollziehbares Phänomen gestossen.


int ja = 0, nein = 0;

while (ja < 1000 && nein < 1000) {
	if (random.nextInt() % 2 == 1) {
		ja++;
	} else {
		nein++;
	}
}

System.out.println("Ja: " + ja + ", Nein: " + nein);```

**Jedes** Mal bei der Ausführung kommt der Nein-Zähler auf 1000 und der Ja-Zähler nur auf knapp 350. Der Hammer ist aber, wenn ich die sechste Zeile von

```	if (random.nextInt() % 2 == 1) {```

nach

```	if (random.nextInt() % 2 == 0) {```

ändere, sind die Zähler wieder gleichmässig verteilt (beide ungefähr bei 1000).

Um es kurz zusammenzufassen: Wenn ich eine zufällige Zahl % 2 auf 0 prüfe, liegt alles im normalen Bereich, aber wenn ich das Resultat auf 1 prüfe (und ich ändere wirklich nur diese eine Zahl, alles andere bleibt gleich), gibt es immer massive Abweichungen von der Wahrscheinlichkeit.

Hier 10 Durchläufe, wenn mit 1 verglichen wird:


Ja: 349, Nein: 1000
Ja: 351, Nein: 1000
Ja: 344, Nein: 1000
Ja: 323, Nein: 1000
Ja: 322, Nein: 1000
Ja: 294, Nein: 1000
Ja: 360, Nein: 1000
Ja: 335, Nein: 1000
Ja: 340, Nein: 1000
Ja: 370, Nein: 1000



Und hier 10 Durchläufe, wenn mit 0 verglichen wird:


Ja: 1000, Nein: 975
Ja: 1000, Nein: 948
Ja: 1000, Nein: 956
Ja: 989, Nein: 1000
Ja: 1000, Nein: 965
Ja: 951, Nein: 1000
Ja: 974, Nein: 1000
Ja: 985, Nein: 1000
Ja: 1000, Nein: 982
Ja: 930, Nein: 1000



Weiss jemand, woran das liegt? Oder überseh ich da grad irgendwas total?

Bei negative Zahlen gibt n%2 0 oder -1 zurück. Der Operator % in Java liefert den Rest und nicht den Modulo.

Hast du das schonmal für größere Zahlen probiert? Also 10000 oder 100000 ja’s und nein’s gesammelt?

Der Unterschied bei Änderungen von Zeile 6 macht für mich wenig Sinn, weil dadurch müssten ja und nein einfach nur vertauscht werden.

Versuch mal den Randum Seed selber zu setzen und peobier dann mal für den selben Seed aus, wie es sich ändert, wenn du Zeile 6 ändderst.

Erst habe ich auch kurz überlegt, aber Lumaraf dürfte recht haben. Mit sowas wie

int value = random.nextInt() % 2;
if (value == 1) {
    System.out.println("jo "+value);
    ja++;
} else {
    System.out.println("nö "+value);
    nein++;
}

würde das schnell auffallen.

Das passt auch zur 3/4 zu 1/4 Verteilung. Wenn man if ((random.nextInt() & 1) == 1) { verwendet, passt es auch mit 1 und macht das, was man erwartet.

@Lumaraf Danke für die Antwort: Du hast vollkommen recht. An die negativen Zahlen hatte ich nicht gedacht.

if (Math.abs(random.nextInt()) % 2 == 1) {

Das liefert jetzt wieder die erwarteten Resultate. Fast unglaublich, die schnelle und kompetente Hilfe hier :slight_smile:

[QUOTE=phpascal]
if (Math.abs(random.nextInt()) % 2 == 1) {

Das liefert jetzt wieder die erwarteten Resultate. Fast unglaublich, die schnelle und kompetente Hilfe hier :)[/QUOTE]

Auch wenn Schlaf- Koffein- und Nahrungsmangel mir da vielleicht gerade einen Streich spielen: Sollte, wenn es -1, 0 und 1 sein kann, und durch das ‘abs’ sowohl -1 als auch 1 auf 1 abgebildet werden, nicht eine 1:2-Verteilung (statt der vermutlich erhofften 1:1-Verteilung) rauskommen? (Müßte ich wohl mal testen…)

Es gibt eine ziemlich genaue 1:1 Verteilung :slight_smile:

Ja: 1000, Nein: 977
Ja: 971, Nein: 1000
Ja: 887, Nein: 1000
Ja: 994, Nein: 1000
Ja: 1000, Nein: 938
Ja: 1000, Nein: 959
Ja: 1000, Nein: 945
Ja: 925, Nein: 1000
Ja: 983, Nein: 1000
Ja: 931, Nein: 1000

Wenn man die Zahlen rein auf -1, 0 und 1 begrenzen würde, hättest du natürlich Recht.

Auch bei den negativen Zahlen ergibt mit Math.abs() die Hälfte aller Zahlen einen Rest von 1 und die andere Hälfte einen Rest von 0. Also genau das, was ich wollte (richtig auf 1:1 spekuliert).

Die 0 wird in 50% der Fälle getroffen, die 1 in 25% und die -1 auch in 25%. Wenn man die -1 und +1 Fälle zusammenzählt, macht das auch 50%.
Die 0 wurde vorher deshalb doppelt so oft getroffen, weil sie sowohl von den geraden negativen als auch positiven Zahlen erwischt wird.

Ohja, hatte da irgendwie was falsch verschaltet, was mit der Option random.nextInt(2) zu tun gehabt hätte :wink:

EDIT: Auch wenn es doch eine ungerade Zahl mehr gibt, oder? (Ach, schon wieder überlegen, viel zu heiß dafür :o )

Da würde ich zustimmen, auch wenn ich die kleinst / grösstmöglichen Zahlen nicht kenne, die generiert werden können. Auf jeden Fall sind es Millionen von Zahlen, die getroffen werden könnten, da macht eine weniger oder mehr praktisch keinen Unterschied, oder?

Wohl war, aber random.nextInt(2) wirkt sauberer.

Man merkts :smiley: es gibt keine Ungerade Zahl mehr. Welche sollte das sein? Es gibt eine gerade Anzahl an Zahlen, die niedrigste ist gerade (-2^{b-1}), die größte ist ungerade (2^{b-1}-1).

Edit: @EagleEye : das Tex-Plugin funktioniert hier auch noch nicht :wink:

Da sollte das stehen: [tex]-2^{b-1}[/tex] und [tex]2^{b-1}-1[/tex]

Das bezog sich darauf, dass es 2147483648 eben nicht gibt. Zu sagen, dass es deswegen eine ungerade Zahl mehr gibt, weil ich die 0 in diesem Fall nicht mitgezählt habe, würde es wohl nicht besser machen. Zeit für’s Wochenende :wink:

man sollte vorher vielleicht mal einen blick in den duden werfen

Modulo berechnet den Rest b der Division n geteilt durch m.

ergo : das wort „Modulo“ bzw „Modulus“ bezeichnet „den rest einer Division“

deine aussage, das „%“ in Java also den „rest einer Division“ und nicht „den Modulo“ zurückgibt ist mal sowas von einfach nur dermaßen falsch
wenn man schon den „rechtschreib-nazi“ spielen will sollte man sich vielleicht vorher mal selbst das durchlesen was man gerade für einen müll geschrieben hat

Aber er hat Recht, dass der %-Operator nicht dem mathematischen Modulo entspricht.
Das Ergebnis des mathematischen Modulo ist laut Definition immer positiv. Der %-Operator kann, wie weiter oben schon beschrieben, auch negative Werte zurückgeben. So “dermaßen falsch” ist seine Aussage also nicht…

Tja, man unterscheidet da eben, was soll man machen. Man sollte irgendwie klarmachen, welches Vorzeichen das Ergebnis hat, indem man geeignete Begriffe wählt, und solange klar definiert ist, was mit dem einen oder anderen gemeint ist, ist das ja in Ordnung. Schau’ vielleicht mal auf http://de.wikipedia.org/wiki/Division_mit_Rest#Implementierung_in_Computersystemen , oder in den Duden, falls du da ähnliche Informationen zu finden glaubst.