Dies rand()
gilt auch für einen Pseudozufallszahlengenerator, der eine natürliche Zahl zwischen 0 und wählt RAND_MAX
, eine Konstante, die in definiert ist cstdlib
(siehe diesen Artikel für eine allgemeine Übersicht überrand()
).
Was passiert nun, wenn Sie eine Zufallszahl zwischen 0 und 2 generieren möchten? Nehmen wir zur Erklärung an, es RAND_MAX
ist 10, und ich beschließe, durch Aufrufen eine Zufallszahl zwischen 0 und 2 zu generieren rand()%3
. Erzeugt rand()%3
jedoch nicht die Zahlen zwischen 0 und 2 mit gleicher Wahrscheinlichkeit!
Wenn rand()
0, 3, 6 oder 9 zurückgegeben wird , rand()%3 == 0
. Daher ist P (0) = 4/11
Wenn rand()
1, 4, 7 oder 10 zurückgegeben wird , rand()%3 == 1
. Daher ist P (1) = 4/11
Wenn rand()
2, 5 oder 8 zurückgegeben wird , rand()%3 == 2
. Daher ist P (2) = 3/11
Dies erzeugt nicht die Zahlen zwischen 0 und 2 mit gleicher Wahrscheinlichkeit. Natürlich ist dies für kleine Bereiche möglicherweise nicht das größte Problem, aber für einen größeren Bereich kann dies die Verteilung verzerren und die kleineren Zahlen beeinflussen.
Wann wird also rand()%n
mit gleicher Wahrscheinlichkeit ein Zahlenbereich von 0 bis n-1 zurückgegeben? Wann RAND_MAX%n == n - 1
. In diesem Fall wird zusammen mit unserer früheren Annahme rand()
eine Zahl zwischen 0 und 0 zurückgegebenRAND_MAX
mit gleicher Wahrscheinlichkeit auch die Moduloklassen von n gleichmäßig verteilt sein.
Wie lösen wir dieses Problem? Eine grobe Methode besteht darin, so lange Zufallszahlen zu generieren, bis Sie eine Zahl in Ihrem gewünschten Bereich erhalten:
int x;
do {
x = rand();
} while (x >= n);
Dies ist jedoch für niedrige Werte von ineffizient n
, da Sie nur die n/RAND_MAX
Chance haben, einen Wert in Ihrem Bereich zu erhalten, und Sie daher RAND_MAX/n
Anrufe bei tätigen müssenrand()
durchschnittlich .
Eine effizientere Formel Ansatz wäre, eine große Strecke mit einer Länge teilbar zu nehmen , indem n
, wie RAND_MAX - RAND_MAX % n
, halten Zufallszahlen zu erzeugen , bis Sie ein , dass liegt im Bereich, und dann den Modul nehmen:
int x;
do {
x = rand();
} while (x >= (RAND_MAX - RAND_MAX % n));
x %= n;
Für kleine Werte von n
erfordert dies selten mehr als einen Aufruf von rand()
.
Zitierte Werke und weiterführende Literatur:
RAND_MAX%n == n - 1
_ _ nachzudenken, ist(RAND_MAX + 1) % n == 0
. Wenn ich Code lese, verstehe ich ihn eher% something == 0
als „gleichmäßig teilbar“ als andere Berechnungsmethoden. Wenn Ihre C ++ - stdlibRAND_MAX
den gleichen Wert wie hatINT_MAX
,(RAND_MAX + 1)
würde dies natürlich nicht funktionieren. Daher bleibt Marks Berechnung die sicherste Implementierung.Die Auswahl eines Zufalls ist ein guter Weg, um die Verzerrung zu beseitigen.
Aktualisieren
Wir könnten den Code schnell machen, wenn wir nach einem x im Bereich suchen, der durch teilbar ist
n
.Die obige Schleife sollte sehr schnell sein, beispielsweise durchschnittlich 1 Iteration.
quelle
rand()
können, kein Vielfaches von istn
, erhalten Sie bei allem, was Sie tun, unweigerlich eine "Modulo-Verzerrung", es sei denn, Sie verwerfen einige dieser Werte. user1413793 erklärt das gut (obwohl die in dieser Antwort vorgeschlagene Lösung wirklich glücklich ist).RAND_MAX+1 - (RAND_MAX+1) % n
funktioniert die Arbeit korrekt, aber ich denke immer noch, dass sieRAND_MAX+1 - ((RAND_MAX+1) % n)
aus Gründen der Klarheit geschrieben werden sollte.RAND_MAX == INT_MAX
(wie auf den meisten Systemen) . Siehe meinen zweiten Kommentar zu @ user1413793 oben.@ user1413793 ist bezüglich des Problems korrekt. Ich werde das nicht weiter diskutieren, außer um einen Punkt zu machen: Ja, für kleine Werte
n
und große Werte vonRAND_MAX
kann die Modulo-Vorspannung sehr klein sein. Die Verwendung eines Bias-induzierenden Musters bedeutet jedoch, dass Sie die Bias jedes Mal berücksichtigen müssen, wenn Sie eine Zufallszahl berechnen und unterschiedliche Muster für verschiedene Fälle auswählen. Und wenn Sie die falsche Wahl treffen, sind die darin enthaltenen Fehler subtil und für Unit-Tests fast unmöglich. Verglichen mit der Verwendung des richtigen Werkzeugs (z. B.arc4random_uniform
) ist dies zusätzliche Arbeit, nicht weniger Arbeit. Mehr Arbeit zu leisten und eine schlechtere Lösung zu finden, ist eine schreckliche Technik, besonders wenn es auf den meisten Plattformen einfach ist, es jedes Mal richtig zu machen.Leider sind die Implementierungen der Lösung alle falsch oder weniger effizient als sie sein sollten. (Jede Lösung enthält verschiedene Kommentare, in denen die Probleme erläutert werden, aber keine der Lösungen wurde behoben, um sie zu beheben.) Dies kann den gelegentlichen Antwortsuchenden verwirren. Daher biete ich hier eine bekanntermaßen gute Implementierung an.
Auch hier ist die beste Lösung die Verwendung
arc4random_uniform
auf Plattformen, die sie bereitstellen, oder eine ähnliche Fernkampflösung für Ihre Plattform (z. B.Random.nextInt
auf Java). Es wird das Richtige ohne Codekosten für Sie tun. Dies ist fast immer der richtige Anruf.Wenn dies nicht der Fall ist,
arc4random_uniform
können Sie die Leistung von Open Source nutzen, um genau zu sehen, wie es auf einem RNG mit größerer Reichweite implementiert wird (ar4random
in diesem Fall könnte ein ähnlicher Ansatz jedoch auch auf anderen RNGs funktionieren).Hier ist die OpenBSD-Implementierung :
Es ist erwähnenswert, dass der neueste Commit-Kommentar zu diesem Code für diejenigen gedacht ist, die ähnliche Dinge implementieren müssen:
Die Java-Implementierung ist auch leicht zu finden (siehe vorherigen Link):
quelle
arcfour_random()
die Ausgabe definitiv eine gewisse Verzerrung aufweist , wenn tatsächlich der echte RC4-Algorithmus in seiner Implementierung verwendet wird. Hoffentlich haben Ihre Bibliotheksautoren auf die Verwendung eines besseren CSPRNG hinter derselben Schnittstelle umgestellt. Ich erinnere mich, dass eines der BSDs jetzt tatsächlich den ChaCha20-Algorithmus zur Implementierung verwendetarcfour_random()
. Weitere Informationen/dev/random
in der Vergangenheit auch RC4 auf einigen Plattformen verwendet (Linux verwendet SHA-1 im Zählermodus). Leider weisen die über die Suche gefundenen Manpages darauf hin, dass RC4 auf verschiedenen angebotenen Plattformen noch verwendet wirdarc4random
(obwohl der tatsächliche Code möglicherweise unterschiedlich ist).-upper_bound % upper_bound == 0
??-upper_bound % upper_bound
in der Tat 0, wennint
es breiter als 32 Bit ist. Es sollte sein(u_int32_t)-upper_bound % upper_bound)
(vorausgesetzt, esu_int32_t
ist ein BSD-Ismus füruint32_t
).Definition
Modulo Bias ist die inhärente Vorspannung bei der Verwendung von Modulo-Arithmetik, um einen Ausgangssatz auf eine Teilmenge des Eingangssatzes zu reduzieren. Im Allgemeinen liegt eine Vorspannung vor, wenn die Zuordnung zwischen dem Eingabe- und dem Ausgabesatz nicht gleichmäßig verteilt ist, wie im Fall der Verwendung der Modulo-Arithmetik, wenn die Größe des Ausgabesatzes kein Teiler der Größe des Eingabesatzes ist.
Diese Verzerrung ist besonders schwer zu vermeiden, wenn Zahlen als Bitfolgen dargestellt werden: 0s und 1s. Es ist ebenfalls äußerst schwierig, wirklich zufällige Zufallsquellen zu finden, die jedoch den Rahmen dieser Diskussion sprengen. Nehmen Sie für den Rest dieser Antwort an, dass es eine unbegrenzte Quelle für wirklich zufällige Bits gibt.
Problembeispiel
Betrachten wir die Simulation eines Würfelwurfs (0 bis 5) mit diesen zufälligen Bits. Es gibt 6 Möglichkeiten, also brauchen wir genug Bits, um die Zahl 6 darzustellen, die 3 Bits ist. Leider ergeben 3 zufällige Bits 8 mögliche Ergebnisse:
Wir können die Größe des Ergebnissatzes auf genau 6 reduzieren, indem wir den Wert modulo 6 nehmen. Dies stellt jedoch das Modulo-Bias- Problem dar:
110
ergibt eine 0 und111
ergibt eine 1. Dieser Würfel wird geladen.Potentielle Lösungen
Ansatz 0:
Anstatt sich auf zufällige Bits zu verlassen, könnte man theoretisch eine kleine Armee einstellen, die den ganzen Tag würfelt und die Ergebnisse in einer Datenbank aufzeichnet und dann jedes Ergebnis nur einmal verwendet. Dies ist ungefähr so praktisch, wie es sich anhört, und würde höchstwahrscheinlich sowieso keine wirklich zufälligen Ergebnisse liefern (Wortspiel beabsichtigt).
Ansatz 1:
Anstatt das Modul zu verwenden, eine naive , aber mathematisch korrekte Lösung ist zu verwerfen Ergebnisse , dass Ausbeute
110
und111
und einfach versuchen Sie es erneut mit 3 neuen Bits. Leider bedeutet dies, dass bei jedem Wurf eine 25% ige Chance besteht, dass ein erneuter Wurf erforderlich ist, einschließlich jedes der erneuten Würfe selbst. Dies ist eindeutig unpraktisch für alle außer den trivialsten Verwendungen.Ansatz 2:
Verwenden Sie mehr Bits: Verwenden Sie anstelle von 3 Bits 4. Dies ergibt 16 mögliche Ergebnisse. Ein erneutes Rollen, wenn das Ergebnis größer als 5 ist, macht die Sache natürlich noch schlimmer (10/16 = 62,5%), so dass allein nichts hilft.
Beachten Sie, dass 2 * 6 = 12 <16 ist, sodass wir sicher jedes Ergebnis unter 12 nehmen und dieses Modulo 6 reduzieren können, um die Ergebnisse gleichmäßig zu verteilen. Die anderen 4 Ergebnisse müssen verworfen und dann wie im vorherigen Ansatz erneut gewürfelt werden.
Hört sich zunächst gut an, aber lassen Sie uns die Mathematik überprüfen:
Dieses Ergebnis ist unglücklich, aber versuchen wir es noch einmal mit 5 Bits:
Eine deutliche Verbesserung, aber in vielen praktischen Fällen nicht gut genug. Die gute Nachricht ist, dass das Hinzufügen weiterer Bits niemals die Wahrscheinlichkeit erhöht, dass ein Abwurf und ein erneuter Wurf erforderlich sind . Dies gilt nicht nur für Würfel, sondern in allen Fällen.
Wie gezeigt , ändert das Hinzufügen eines zusätzlichen Bits möglicherweise nichts. Wenn wir unseren Roll auf 6 Bit erhöhen, bleibt die Wahrscheinlichkeit 6,25%.
Dies wirft 2 zusätzliche Fragen auf:
Allgemeine Lösung
Zum Glück lautet die Antwort auf die erste Frage ja. Das Problem mit 6 ist, dass 2 ^ x mod 6 zwischen 2 und 4 wechselt, die zufällig ein Vielfaches von 2 voneinander sind, so dass für ein gerades x> 1
Somit ist 6 eher eine Ausnahme als die Regel. Es ist möglich, größere Module zu finden, die auf die gleiche Weise aufeinanderfolgende Potenzen von 2 ergeben, aber letztendlich muss dies umlaufen, und die Wahrscheinlichkeit eines Verwerfens wird verringert.
Konzeptioneller Beweiß
Hier ist ein Beispielprogramm, das OpenSSLs libcrypo verwendet, um zufällige Bytes bereitzustellen. Stellen Sie beim Kompilieren sicher, dass Sie eine Verknüpfung zu der Bibliothek herstellen, mit
-lcrypto
der fast jeder verfügbar sein sollte.Ich empfehle, mit den Werten
MODULUS
und zu spielenROLLS
, um zu sehen, wie viele Wiederholungen unter den meisten Bedingungen tatsächlich stattfinden. Eine skeptische Person möchte möglicherweise auch die berechneten Werte in einer Datei speichern und überprüfen, ob die Verteilung normal erscheint.quelle
randomPool = RAND_bytes(...)
Zeile führtrandomPool == 1
aufgrund der Behauptung immer zu. Dies führt immer zu einem Abwurf und einem erneuten Wurf. Ich denke, Sie wollten in einer separaten Zeile deklarieren. Infolgedessen kehrte das RNG bei1
jeder Iteration zurück.randomPool
wird immer1
nach der OpenSSL- DokumentationRAND_bytes()
ausgewertet, da es dank derRAND_status()
Behauptung immer erfolgreich sein wird .Es gibt zwei übliche Beschwerden bei der Verwendung von Modulo.
Einer gilt für alle Generatoren. In einem Grenzfall ist es leichter zu erkennen. Wenn Ihr Generator einen RAND_MAX hat, der 2 ist (was nicht dem C-Standard entspricht) und Sie nur 0 oder 1 als Wert möchten, generiert modulo 0 doppelt so oft (wenn der Generator 0 und 2 generiert) wie es ist 1 generieren (wenn der Generator 1 generiert). Beachten Sie, dass dies der Fall ist, sobald Sie keine Werte löschen, unabhängig von der Zuordnung, die Sie von den Generatorwerten zu den gewünschten verwenden, eine doppelt so häufig wie die andere.
Bei einigen Generatoren sind die weniger signifikanten Bits weniger zufällig als bei den anderen, zumindest für einige ihrer Parameter. Leider weisen diese Parameter andere interessante Eigenschaften auf (z. B. kann RAND_MAX eine weniger als eine Potenz von 2 haben). Das Problem ist bekannt und für eine lange Zeit vermeiden Bibliotheksimplementierungen wahrscheinlich das Problem (zum Beispiel verwendet die Beispiel-Implementierung von rand () im C-Standard diese Art von Generator, lässt aber die 16 weniger signifikanten Bits fallen), aber einige beschweren sich gerne darüber das und Sie können Pech haben
Mit so etwas wie
Das Generieren einer Zufallszahl zwischen 0 und n vermeidet beide Probleme (und vermeidet einen Überlauf mit RAND_MAX == INT_MAX).
Übrigens führte C ++ 11 Standardmethoden für die Reduktion und andere Generatoren als rand () ein.
quelle
Marks Lösung (die akzeptierte Lösung) ist nahezu perfekt.
Es gibt jedoch eine Einschränkung, die 1 gültigen Satz von Ergebnissen in jedem Szenario verwirft, in dem
RAND_MAX
(RM
) 1 weniger als ein Vielfaches vonN
(wobeiN
= die Anzahl möglicher gültiger Ergebnisse) ist.dh wenn die 'Anzahl der verworfenen Werte' (
D
) gleich istN
, dann sind sie tatsächlich eine gültige Menge (V)
keine ungültige Menge (I
).Was dies verursacht, ist, dass Mark irgendwann den Unterschied zwischen
N
und aus den Augen verliertRand_Max
.N
ist eine Menge, deren gültige Mitglieder nur aus positiven Ganzzahlen bestehen, da sie eine Anzahl von Antworten enthält, die gültig wären. (zB: SetN
={1, 2, 3, ... n }
)Rand_max
Es handelt sich jedoch um eine Menge, die (wie für unsere Zwecke definiert) eine beliebige Anzahl nicht negativer Ganzzahlen enthält.In seiner allgemeinsten Form wird hier
Rand Max
die Menge aller gültigen Ergebnisse definiert, die theoretisch negative Zahlen oder nicht numerische Werte enthalten können.Daher
Rand_Max
ist besser definiert als die Menge der "möglichen Antworten".Jedoch
N
arbeitet gegen die Zählung der Werte innerhalb des Satzes von gültigen Antworten, so auch wie in unserem speziellen Fall definiert ist ,Rand_Max
wird ein Wert um eins kleiner als die Gesamtzahl sei es enthält.Bei Verwendung von Marks Lösung werden Werte verworfen, wenn: X => RM - RM% N.
Wie Sie im obigen Beispiel sehen können, würden wir den Wert von X (die Zufallszahl, die wir aus der Anfangsfunktion erhalten) 252, 253, 254 oder 255 verwerfen, obwohl diese vier Werte einen gültigen Satz zurückgegebener Werte enthalten .
IE: Wenn die Anzahl der verworfenen Werte (I) = N (die Anzahl der gültigen Ergebnisse) ist, wird ein gültiger Satz von Rückgabewerten von der ursprünglichen Funktion verworfen.
Wenn wir den Unterschied zwischen den Werten N und RM als D beschreiben, dh:
Wenn dann der Wert von D kleiner wird, steigt der Prozentsatz der nicht benötigten Nachwürfe aufgrund dieser Methode bei jedem natürlichen Multiplikativ. (Wenn RAND_MAX NICHT gleich einer Primzahl ist, ist dies von berechtigter Bedeutung.)
Z.B:
Da der Prozentsatz der benötigten Rerolls zunimmt, je näher N an RM kommt, kann dies bei vielen verschiedenen Werten von Bedeutung sein, abhängig von den Einschränkungen des Systems, auf dem der Code ausgeführt wird, und den gesuchten Werten.
Um dies zu negieren, können wir eine einfache Änderung vornehmen, wie hier gezeigt:
Dies bietet eine allgemeinere Version der Formel, die die zusätzlichen Besonderheiten der Verwendung des Moduls zur Definition Ihrer Maximalwerte berücksichtigt.
Beispiele für die Verwendung eines kleinen Werts für RAND_MAX, der ein Multiplikativ von N ist.
Mark'original Version:
Verallgemeinerte Version 1:
In dem Fall, in dem N die Anzahl der Werte in RAND_MAX sein soll; In diesem Fall können Sie N = RAND_MAX +1 setzen, es sei denn, RAND_MAX = INT_MAX.
In Bezug auf die Schleife können Sie einfach N = 1 verwenden, und jeder Wert von X wird jedoch akzeptiert, und Sie geben eine IF-Anweisung für Ihren endgültigen Multiplikator ein. Aber vielleicht haben Sie Code, der einen gültigen Grund hat, eine 1 zurückzugeben, wenn die Funktion mit n = 1 aufgerufen wird ...
Daher ist es möglicherweise besser, 0 zu verwenden, was normalerweise einen Div 0-Fehler liefert, wenn Sie n = RAND_MAX + 1 haben möchten
Verallgemeinerte Version 2:
Beide Lösungen lösen das Problem mit unnötig verworfenen gültigen Ergebnissen, die auftreten, wenn RM + 1 ein Produkt von n ist.
Die zweite Version behandelt auch das Edge-Case-Szenario, wenn Sie n benötigen, um dem insgesamt möglichen Wertesatz in RAND_MAX zu entsprechen.
Der modifizierte Ansatz ist in beiden Fällen derselbe und ermöglicht eine allgemeinere Lösung für die Notwendigkeit, gültige Zufallszahlen bereitzustellen und verworfene Werte zu minimieren.
Wiederholen:
Die grundlegende allgemeine Lösung, die das Beispiel der Marke erweitert:
Die erweiterte allgemeine Lösung, die ein zusätzliches Szenario von RAND_MAX + 1 = n ermöglicht:
In einigen Sprachen (insbesondere interpretierten Sprachen) kann die Berechnung der Vergleichsoperation außerhalb der while-Bedingung zu schnelleren Ergebnissen führen, da dies eine einmalige Berechnung ist, unabhängig davon, wie viele Versuche erforderlich sind. YMMV!
quelle
RAND_MAX%n = n - 1
Bei einem
RAND_MAX
Wert von3
(in Wirklichkeit sollte er viel höher sein, aber die Verzerrung würde immer noch bestehen) ist es aus diesen Berechnungen sinnvoll, dass eine Verzerrung vorliegt:1 % 2 = 1
2 % 2 = 0
3 % 2 = 1
random_between(1, 3) % 2 = more likely a 1
In diesem Fall
% 2
sollten Sie dies nicht tun, wenn Sie eine Zufallszahl zwischen0
und möchten1
. Sie könnten eine Zufallszahl zwischen bekommen0
und2
indem% 3
aber, weil in diesem Fall:RAND_MAX
ein Vielfaches3
.Eine andere Methode
Es ist viel einfacher, aber um andere Antworten zu ergänzen, hier ist meine Lösung, um eine Zufallszahl zwischen
0
undn - 1
, alson
verschiedene Möglichkeiten, ohne Verzerrung zu erhalten.>= n
, starten Sie neu (kein Modulo).Wirklich zufällige Daten sind nicht einfach zu erhalten. Warum also mehr Bits als nötig verwenden?
Unten sehen Sie ein Beispiel in Smalltalk, bei dem ein Bit-Cache eines Pseudozufallszahlengenerators verwendet wird. Ich bin kein Sicherheitsexperte. Die Verwendung erfolgt auf eigenes Risiko.
quelle
Wie die akzeptierte Antwort zeigt, hat "Modulo Bias" seine Wurzeln im niedrigen Wert von
RAND_MAX
. Er verwendet einen extrem kleinen Wert vonRAND_MAX
(10), um zu zeigen, dass, wenn RAND_MAX 10 wäre, Sie versucht hätten, mit% eine Zahl zwischen 0 und 2 zu generieren, die folgenden Ergebnisse resultieren würden:Es gibt also 4 Ausgänge von 0 (4/10 Chance) und nur 3 Ausgänge von 1 und 2 (jeweils 3/10 Chancen).
Es ist also voreingenommen. Die niedrigeren Zahlen haben eine bessere Chance herauszukommen.
Aber das zeigt sich nur so offensichtlich, wenn
RAND_MAX
es klein ist . Oder genauer gesagt, wenn die Anzahl, nach der Sie modifizieren, im Vergleich zu groß istRAND_MAX
.Eine viel bessere Lösung als eine Schleife (die wahnsinnig ineffizient ist und nicht einmal vorgeschlagen werden sollte) ist die Verwendung eines PRNG mit einem viel größeren Ausgabebereich. Der Mersenne Twister- Algorithmus hat eine maximale Leistung von 4.294.967.295. Als solches wird das Tun
MersenneTwister::genrand_int32() % 10
in jeder Hinsicht gleichmäßig verteilt und der Modulo-Bias-Effekt wird so gut wie verschwinden.quelle
MT::genrand_int32()%2
0 (50 + 2,3e-8)% der Zeit und 1 (50 - 2,3e-8)% der Zeit ausgewählt. Sofern Sie nicht die RGN eines Casinos erstellen (für die Sie wahrscheinlich eine RGN mit viel größerer Reichweite verwenden würden), wird kein Benutzer in den meisten Fällen zusätzliche 2,3e-8% bemerken. Sie sprechen von Zahlen, die zu klein sind, um hier eine Rolle zu spielen.RAND_MAX
Werts verringert die Modulo-Vorspannung, beseitigt sie jedoch nicht. Looping wird.RAND_MAX
es ausreichend größer ist als die Zahl, mit der Sie modifizieren, ist die Häufigkeit, mit der Sie die Zufallszahl neu generieren müssen, verschwindend gering und beeinträchtigt die Effizienz nicht. Ich sage, behalte die Schleife bei, solange du gegen das größte Vielfache vonn
testest und nicht nur so,n
wie es die akzeptierte Antwort vorschlägt.Ich habe gerade einen Code für Von Neumanns Unbiased Coin Flip-Methode geschrieben, der theoretisch jegliche Verzerrung bei der Zufallszahlengenerierung beseitigen sollte. Weitere Infos finden Sie unter ( http://en.wikipedia.org/wiki/Fair_coin )
quelle
rand() % 100
100-maliger Aufruf . B) Wenn alle Ergebnisse unterschiedlich sind, nehmen Sie das erste. C) Andernfalls GOTO A. Dies wird funktionieren, aber mit einer erwarteten Anzahl von Iterationen von ungefähr 10 ^ 42 müssen Sie ziemlich geduldig sein. Und unsterblich.else if(prev==2) prev= x1; else { if(prev!=x1) return prev; prev=2;}