Obwohl es hier viele Code-Golf-Fragen gibt, bei denen es um Zufälligkeit geht, habe ich noch keine gesehen, bei der es darum geht, einen algorithmischen Pseudozufallszahlengenerator zu erstellen. Es gibt diesen , der Sie bittet, einen Bit-Stream zu generieren, aber die darin enthaltenen Zufallstests waren nicht sehr streng und es ist kein Code-Golf.
Das Programm, das Sie schreiben, verfügt über eine einzelne aufrufbare Funktion, die eine zufällige Ganzzahl von 0 bis 4294967295 zurückgibt. Diese Funktion darf keine Bibliotheken oder andere Funktionen aufrufen, die nicht als Teil des Programms geschrieben wurden, insbesondere Aufrufe von / dev / random oder die eingebaute rand () Bibliothek einer Sprache. Insbesondere sind Sie auf die grundlegenden Operatoren der Sprache beschränkt, in der Sie arbeiten, z. B. Arithmetik, Array-Zugriff und Anweisungen zur bedingten Flusssteuerung.
Die Punktzahl Ihres Programms wird wie folgt berechnet:
Score = C / R
Wobei C die Länge des Codes in Zeichen und R die Anzahl der von Ihrem Generator bestandenen Diehard-Tests ist (Wenn Ihr Zufallsgenerator nicht mindestens einen Diehard-Test besteht, ist seine Punktzahl unendlich und wird disqualifiziert). Ihr Generator besteht einen Diehard-Test, wenn die erzeugte Datei einen Bereich von P-Werten enthält, die gleichmäßig über das Intervall verteilt zu sein scheinen [0, 1).
Verwenden Sie zur Berechnung von R Ihren Zufallszahlengenerator mit seinem Standard-Startwert, um eine 16-MB-Binärdatendatei zu generieren. Jeder Aufruf der Funktion gibt vier Bytes zurück. Wenn Ihre Funktion zu langsam ist, um Bytes zurückzugeben, wird dies einen Kompromiss zum Erreichen einer niedrigen Punktzahl berücksichtigen, indem festgestellt wird, wie schwierig der Test ist. Führen Sie dann die Diehard-Tests durch und überprüfen Sie die angegebenen P-Werte. (Versuchen Sie nicht, diese selbst zu implementieren; verwenden Sie die hier bereitgestellten )
Die niedrigste Punktzahl gewinnt natürlich.
quelle
Antworten:
Mathematica, 32/15 = 2,133
Eine unkomplizierte Implementierung von BBS .
Binärdatei generiert mit:
Zusammenfassung der Ergebnisse:
Voll
random.bin
hier.Vollständige Protokolldatei hier.
quelle
28!-67
ist etwas unerschwinglich. Gibt es einen kleineren Wert, der in eine 64-Bit-Ganzzahl passt?Perl 28/13 ≈ 2.15
Logdatei hier
Perl 29/13 ≈ 2.23
Logdatei hier
Dies ist eine Art Variation einer Xorshift-Funktion , bei der anstelle einer Rechtsverschiebung eine Gleitkommadivision verwendet wird. Beide haben 13 von 15 Tests bestanden und nur die Tests 6 und 7 nicht bestanden.
Ich bin mir nicht ganz sicher , wie lange der Zyklus ist, sondern weil der folgende Code in keiner kurzen Zeit nicht beenden, ist es wahrscheinlich die volle 2 32 :
Perl 39/10 = 3,9
Hinweis: Wenn Sie nach einem Blum-Blum-Shub-ähnlichen PRNG suchen, ist die Lösung von Keith Randall weitaus besser als jede dieser Lösungen .
Wie bei meiner ursprünglichen Lösung unten handelt es sich auch hier um eine Implementierung von Blum Blum Shub, mit einem großen Unterschied. Ich verwende ein Modul, das etwas größer als 2 32 ist ( M = 50971 • 84263 ). Wenn ein Wert gefunden wird, der keine gültige 32-Bit-Ganzzahl ist ( dh größer als 2 32 ), wird der nächste Wert in der zurückgegeben Rotation statt. Im Wesentlichen werden diese Werte herausgeschnitten, so dass der Rest der Rotation ungestört bleibt, was zu einer nahezu gleichmäßigen Verteilung führt.
Es scheint geholfen zu haben. Er besteht nicht nur die gleichen 9 Tests wie zuvor, sondern besteht jetzt auch überzeugend den Mindestabstandstest. Eine Beispielprotokolldatei finden Sie hier .
Perl 33/9 ≈ 3.67 (Ungültig?)
Hinweis: Diese Lösung kann als ungültig angesehen werden, da die obersten 0,00037% des Bereichs niemals eingehalten werden.
Eine schnelle und schmutzige Implementierung des Blum Blum Shub . Ich behaupte die folgenden Ergebnisse:
Eine Beispielprotokolldatei finden Sie hier. Sie können die Ergebnisse jederzeit beanstanden. Die Datei für diehard kann auf folgende Weise generiert werden:
und dann die Ausgabe in eine Datei umleiten. Der Mindestabstand scheint verstrichen zu sein, aber wenn Sie ihn mehrmals ausführen, liegt er immer nahe bei 1,0 , was auf einen Fehler hinweist.
Einzelheiten
Im Allgemeinen ist der Blum Blum Shub ein schrecklicher PRNG, aber seine Leistung kann durch Auswahl eines guten Moduls verbessert werden. Das von mir gewählte M ist 7027 • 611207 . Beide Primfaktoren, p und q , haben den modularen Rest 3 (mod 4) und gcd (p (p-1), φ (q-1)) = 2 , was so niedrig wie möglich ist.
Obwohl dies die einzigen Kriterien sind, die auf der Wiki-Seite aufgelistet sind, scheint es nicht genug zu sein. Fast das gesamte Modulo, das ich ausprobiert habe, ist bei jedem Test durchgefallen. Aber es gibt eine Handvoll, die einige der Tests bestehen wird, und die, die ich ausgewählt habe, scheint aus irgendeinem Grund außergewöhnlich gut zu sein.
Als letzte Anmerkung scheint Test 5 für sich genommen ein ziemlich guter Indikator dafür zu sein, wie gut der PRNG ist. Wenn es Test 5 nicht fast besteht , wird es den Rest von ihnen spektakulär verfehlen.
BONUS: Perl 62/14 ≈ 4,43
Nur für Geekery ist dies eine 32-Bit-Version des PRNG, das im ursprünglichen Tetris für NES verwendet wird. Erstaunlicherweise besteht es 14 der 15 Tests!
Beispielprotokolldatei kann vorher hier stehen .
Zugegeben, das
1..37
Bit ist keine exakte Transkription. In der ursprünglichen Version wird die Entropieroutine 60 Mal pro Sekunde aktualisiert und dann in zufälligen Intervallen abgefragt, was weitgehend von Benutzereingaben abhängt. Für alle, die den ROM zerlegen möchten, beginnt die Entropieroutine bei0xAB47
.Python-artiger Pseudocode:
quelle
Python, 46/15 = 3,0666
Verwendet modulare Exponentiation, um Zufälligkeit zu erzeugen. 2 ** 32-5 ist die größte Primzahl unter 2 ^ 32. (Gleiches gilt, wenn Test 2 nicht ausgeführt werden kann.)
quelle
\r
und\n
nach\r\n
umzuwandeln, was die Ergebnisse offensichtlich verzerrt. Ein Fix besteht darin, die Datei direkt mitf = open('file.bin', 'wb')
und zu schreibenf.write
.Ruby, 32/15 = 2,1333
Dies ist die in Ruby implementierte Lösung von Keith Randall.
quelle
C # 144/15 = 9,6
Dies hat alle Tests bestanden.
Mit nicht zu vielen weiteren Zeichen besteht es TestU01.
Ergebnis: http://codepad.org/iny6usjV
quelle
C # - 103/14 = 7,36
Ergebnisse
Besteht alle mit Ausnahme von Test Nr. 6. Die
Ergebnisse finden Sie unter http://codepad.org/k1NSoyQW
Erläuterung
C # kann einfach nicht mit Ruby und Python um Knappheit konkurrieren, aber ich habe es genossen, es zu versuchen. Es gibt sicherlich andere Werte, die genauso gut funktionieren (dh der Anfangswert für j = 999 und der Divisor = 277). Ich habe diese nach kurzem Experimentieren ausgewählt.
Mit Wrapper zur Dateierstellung
quelle
Python 41/15 = 2,73333
Irgendwie schummeln mit der eingebauten Hash-Funktion, aber es ist eingebaut, also nicht mehr schummeln als mit anderen eingebauten wie
len
. Auf der anderen Seite schmerzt es mich, für dieglobal v;
Erklärung bezahlen zu müssen ...Besteht alle Diehard-Tests (Ich hatte ein Problem mit Test Nr. 2 (SEGVs) auf meinem OSX-Rechner. Für meine Punktzahl gehe ich davon aus, dass er bestanden wird).
Hier ist ein Treiber zum Generieren der 16MB-Datei:
quelle
+
eine eingebaute Funktion und damit disqualifiziert?+
und__add__
in Python oder Überladen von Operatoren in c ++. Ich weiß, dass ich Haare spalte. Betrachten Sie dieses Beispiel. Kann ich in Python eine Map wie folgt erstellen{'a':5}
:? Sie werden wahrscheinlich ja sagen, aber dann denken Sie daran, dass unter derhash('a')
Decke gerufen wird, wenn Sie das tun.C 38/15 = 2,533
Ich konnte die Diehard-Tests auf meinem Computer nicht zum Laufen bringen, aber es besteht die PractRand-Suite für eine Ausgabe von bis zu 8 GB, sodass ich davon ausgehe, dass alle Tests bestanden werden.
quelle
Brain-Flak , 344 / (ausstehend)
Probieren Sie es online!
Dies funktioniert gut, aber die diehard tests Links sind alle kaputt :( also bis wir neue bekommen, habe ich keine endgültige Punktzahl
Dies verwendet das Blum Blum Shub PRNG, so dass es die meisten Fälle bestehen sollte. Die verwendeten Zahlen sind groß genug. In den 16 MB Testfällen werden keine Muster angezeigt
quelle
Ziel-C, 40/1 = 40
Ziemlich cleverer Ansatz,
.hash
hier etwas auszunutzen , aber ich mag esquelle