Ausgang einer Wahl zufällig bestimmen, Summe soll 100% sein

Hallo,
wie kann man am einfachsten eine Wahl zufällig simulieren bzw. bestimmen? Man übergibt die Anzahl der Parteien (6), und Partei A bekommt z. B. 25 % und Partei D, E und F z. B. 10 %?

Ich weiß leider noch nicht wie, sonst hätte ich Programmcode gepostet.
Danke für eure Hilfe

Schleife mit fixem Endpunkt (20.000 Durchläufe oder mehr?) -> Zufällig eine zur Wahl stehende Alternative auswählen -> Schleife zu Ende laufen lassen -> Absolute Stimmen prozentual auswerten.

Aber dann bräuchte ich 20k Durchläufe(n)… Gibt es keine mathematische Formel (mit 6 Durchläufen)?

Statistisch müsste am Ende jede Partei ungefähr 1/6 der Stimmen bekommen wenn es wirklich nur auf Zufall basiert. Immer.

Außerdem musst du keine 20000 Durchläufe machen, mach doch einfach 100 um die 100% voll zu kriegen.

Wenn man wirklich “unrealistisch” simulieren möchte:

public static double[] votes(int n) {
  // Checks omitted
  double[] votes = new double[n];
  double max = 1d;
  for(int i = 0; i < n - 1; i++) {
    double vote = Math.random() * max;
    votes** = vote;
    max -= vote;
  }
  votes[n - 1] = max;
  return votes;
}

Idee dahinter ist das ständige Verkleinern eines Intervalls [0, 1[ und den Rest der letzten “Partei” zuweisen.

Das Problem dabei ist, dass die erste Partei “0” immer die größte Chance auf die meisten Stimmen hat (100%), jede weitere Partei aber maximal nur noch die restlichen Stimmen ergattern kann und damit die Chance auf Stimmen kleiner wird.

Das sieht man an deinem Codestück sehr deutlich wenn man mal 100 Parteien eingibt. Dein Beispiel funktioniert gerade noch so mit ca. 6 Parteien aber danach sind die Ergebnisse im E-4 bis E-24 Bereich.

Man müsste im nachhinein dann die Parteien zufällig den Ergebnissen zuteilen.

Ich glaube, das von @Flown war das gesuchte.

( Ich weiß nicht, ob ich vor 4 Jahren eine ähnliche Frage schon einmal gestellt hab, und mir das immer zur BT-Wahl einfällt. :wink: )

Das müsste sich genau 50% + 25% + 12,5% + 6,25% + 3,125% + 3,125% = 100 annähern, wenn ich mich nicht irre.

Geht es nicht noch etwas „schiefer“/„unrealistischer“?

A, B, C, D, E, F. Man weist A eine große Wahrscheinlichkeit zu, man weist F eine kleine Wahrscheinlichkeit zu, man weist B eine große Wahrscheinlichkeit zu usw. usf. - Man weist D die Restwahrscheinlichkeit zu. - Oder ist das Nonsens, zu exotisch gedacht?

Mit dem Zufall ist das so eine Sache…

Manche “MP3-Spieler”, die Lieder in “einer zufälligen Reihenfolge” wiedergeben, geben sie gar nicht in einer zufälligen Reihenfolge wieder. “Zufällig” würde bedeuten, dass auch mal 5 mal hintereinander das gleiche Lied kommen kann. Das passiert aber nicht.

Hier könnte man sagen: Man bestimmt 6 Zahlen zwischen 0 und 1, und hat damit die 6 Punkte, an denen man den Kuchen aufteilt. Aber ob das nun “”“echt”"" zufällig ist? Intuitiv ja, aber Intuition kann trügen

Spätestens, wenn man die Verteilung bewußt verzerren will, kann man da ziemlich viel Zeit damit verbringen…

1 „Gefällt mir“

@TMII Darum sagte ich auch “unrealistisch”. Erst viele Stichproben machen es ausgeglichener? oder normalisiert?
Ein viel zu aufwändiges Thema.

Die Idee wollte ich auch vorschlagen und eventuell dann die „Blöcke“ an Stimmen nochmal zufällig an die Parteien zu verteilen, damit nicht das von @TMII erwähnte Problem zu sehr auftritt.

Zwecks den MP3-Playern: Ich habe das Gefühl der Windows Phone Player nimmt mit Absicht nach möglichkeit ein anderen Interpreten als den vorherigen falls es von diesem noch unbenutzte Lieder in der Playlist gibt.

Ich wollte nicht den Zufall infrage stellen, oder seine Funktionsweise, ist mir durchaus bekannt.

Wer hält denn was hiervon?:

    private static float[] m1(int n) {
        float[] array = new float[n];
        float f1 = 1f / n;
        float f2 = 1f;
        Random random = new Random(1);
        for (int i = 0; i < n - 1; i++) {
            float f3 = random.nextFloat() * f1 * 2;
            f2 -= f3;
            array** = f3;
        }
        array[n - 1] = f2;
        return array;
    }

Ergebnis:

  • 24%,
  • 3%,
  • 13%,
  • 13%,
  • 6%,
  • 38%.

(Nachtil: Je größer n, desto langweiliger wird’s!)

	public static double[] votes(int n) {
		double[] rc = new double[n];
		double q = 0;
		double t = 0;
		for(;n > 0; n--) {
			rc[n - 1] = Math.random();
			q += rc[n - 1];
		}
		q /= 100;
		for(n = 0; n < rc.length; n++) {
			rc[n] /= q;
			t += rc[n];
		}
		return rc;
	}

Der Gerechtigkeit gegenüber dem Letzten halber würde ich das vorschlagen. t kannst rausnehmen, sobald du von der Funktion überzeugt bist.

Das erste ist „zu schief“, die letzten beiden sind „zu wenig schief“…

Gibt es nicht noch etwas dazwischen?

Mal in den Raum gefragt: Wie würdet ihr denn einen 2-dimensionalen Berg erstellen?

Dennoch danke ich auch Spacerat. :slight_smile:

Das zweite ist nicht zu wenig schief. Es ist genau so schief, wie die Verteilung der Zufallszahlen normalverteilt ist.
Du kannst die random-Zeile durch folgendes ersetzen

for(int m = 0; m < 20; m++}
  rc[n - 1] += Math.random();
}

und dann mit der 20 experimentieren (200, 2000 aso). Du wirst feststellen, dass der Zufall bei steigenden Grenzwerten immer weniger breit gefächert ist - theoretisch also bei etwa 2^53 (wenn jede mögliche Zufallszahl mindestens ein mal die Chance hatte, generiert zu werden) alle Ergebnisse nahezu den selben Wert aufweisen. Das ist davon abhängig, in wie weit der Zufallsgenerator Zufallszahlen normal- oder gerechtverteilt generiert.

So, Anforderungen:

  • Mindestprozentanzahl (z. B. 9 %),
  • Höchstprozentanzahl (z. B. 25 %),
  • stetiges Gefälle(!).

Was ist denn ein stetiges Gefälle? Wenn Partei A z. B. 25 oder 24 % hat, soll Partei B natürlich weniger % habn.

Ist das „möglich“? (Damit es „spannend“ ist, können die Parteien ja anschließend gemischt werden. :wink: )

    private static int[] m2(int n, int min, int max) {
        int[] array = new int[n];
        int max2 = max;
        Random random = new Random();
        for (int i = 0; i < n; i++) {
            int r = random.nextInt(max2 + 1) * 2;
            if (r < min) {
                r = min;
            }
            if (r > max2) {
                r = max2;
            }
            max2 = r;
            array** = r;
        }
        return array;
    }

Sieht man sich die Ausgabe mal an (int[] array = m2(6, 9, 25);):

[9, 9, 9, 9, 9, 9]
sum = 54
[25, 25, 9, 9, 9, 9]
sum = 86
[25, 10, 9, 9, 9, 9]
sum = 71
[16, 14, 12, 9, 9, 9]
sum = 69
[25, 25, 14, 14, 9, 9]
sum = 96
[25, 12, 9, 9, 9, 9]
sum = 73
[14, 14, 12, 12, 9, 9]
sum = 70
[9, 9, 9, 9, 9, 9]
sum = 54
[20, 14, 14, 14, 9, 9]
sum = 80
[22, 14, 9, 9, 9, 9]
sum = 72

Das stößt mir zu oft an die Ränder. Es müsste ein kleinerer Intervall zufällig gewählt werden. Anderseits solls ja auch nicht streng nach einer Exponentialfunktion (z. B. (1/8)^x) verlaufen.

Damit geht’s:

    /**
     * Danke an Flown und Spacerat.
     * @param n
     * @param min
     * @param max
     * @param random
     * @return
     */
    private static int[] m3(int n, int min, int max, Random random) {
        int[] array = new int[n];
        int max2 = max;
        int sum = 0;
        for (int i = 0; i < n; i++) {
            int r = random.nextInt(max2 - min + 1) + min;
            /*if (r < min) {
                r = min;
            }
            if (r > max2) {
                r = max2;
            }*/
            sum += r;
            max2 = r;
            array** = r;
        }
        for (int i = 0; i < n; i++) {
            array** = (int) (100d / sum * array**);
        }
        return array;
    }
[34, 14, 12, 12, 12, 12]
sum = 96
[26, 16, 16, 15, 13, 12]
sum = 98
[29, 19, 12, 12, 12, 12]
sum = 96
[20, 20, 15, 15, 14, 13]
sum = 97
[20, 20, 19, 14, 12, 11]
sum = 96
[30, 23, 11, 11, 11, 11]
sum = 97
[23, 15, 15, 15, 15, 15]
sum = 98
[24, 22, 18, 12, 11, 9]
sum = 96
[21, 18, 17, 16, 13, 12]
sum = 97
[22, 21, 16, 16, 11, 11]
sum = 97

Das sieht realistisch aus. Je nachdem, wie n, min, und max gewählt werden, kann Partei A auch > max, oder Partei F < min.

Fällt jetzt noch etwas auf? „Oft“ gibt es bei 6 Parteien 4-mal gleiche. :frowning: