Inspiriert von Random mit gebundenen Händen :
Das Ziel
Ziel dieser Herausforderung ist es, ein Programm zu schreiben, das einen pseudozufälligen Bitstrom generiert. Dabei handelt es sich um eine Folge von Einsen und Nullen, die rein zufällig zu sein scheint, aber tatsächlich deterministisch generiert wird. Ihr Programm sollte eine Zeichenfolge von 1 und 0 (mit optionalem Leerzeichen) ausgeben und die folgenden Anforderungen erfüllen:
- Angesichts der unbegrenzten Zeit und des unbegrenzten Speichers muss Ihr Programm für immer eine Zeichenfolge von 1 und 0 ausgeben
- Ihr Programm muss auf einem vernünftigen Computer in etwa einer Minute mehr als 1000 zufällige Bits ausgeben. Wenn diese Anforderung nicht möglich ist, werde ich sie verringern.
- Die Bitfolge kann sich wiederholen, die Länge des Wiederholungsabschnitts muss jedoch mehr als 1000 Bit betragen.
- Die Bitfolge muss so viele Zufallstests wie möglich bestehen (siehe unten).
- Das Programm darf keine Eingaben von externen Quellen entgegennehmen oder eine integrierte rand () - ähnliche Funktion verwenden.
- Aufgrund der obigen Anforderung muss das Programm bei jeder Ausführung genau dieselbe Bitfolge ausgeben.
Zufallstest # 1
Die Folge von Pseudozufallsbits darf bei der Sichtprüfung kein offensichtliches Muster enthalten.
Zufallstest # 2 (Änderungen aufgrund von Kommentaren vorbehalten)
Die Bitfolge muss eine Gleichverteilung von 1 und 0 enthalten. Um dies (und auch andere Dinge) zu testen, wird der Bitstrom in Segmente unterteilt, die 3 Bits lang sind, wie z 101|111|001
.
Von all diesen Segmenten sollten 1/8 drei Einsen und keine Nullen haben, 3/8 sollten zwei Einsen und eine 0 haben, 3/8 sollten eine 1 und zwei Nullen haben und 1/8 von ihnen sollten keine Einsen und drei Nullen haben.
Zufallstest # 3
Ein "Durchlauf" ist definiert als eine aufeinanderfolgende Reihe von Bits, die alle den gleichen Wert haben. Die Saite 1001001110
hat drei Läufe der Größe 1 ( 1..1.....0
), zwei Läufe der Größe 2 ( .00.00....
) und einen Lauf der Größe 3 ( ......111.
). Beachten Sie, dass Läufe nicht überlappen.
Aus einer Folge von 1000 zufälligen Bits sollten ungefähr 250 Läufe der Größe 1, 125 Läufe der Größe 2, 62 Läufe der Größe 3 usw. bestehen. Im Allgemeinen sollten für Laufgröße R ungefähr 1000/(2**(R+1))
Läufe dieser Größe vorhanden sein.
Zufallstest # 4
Die ersten 840 Bits sind in zwei Hälften von jeweils 420 Bits aufgeteilt. Jedes Bit in der ersten Hälfte wird mit dem entsprechenden Bit in der zweiten Hälfte verglichen. Die beiden Bits sollten in etwa fünfzig Prozent der Fälle übereinstimmen.
Hier ist der Quellcode eines Perl-Programms, das die Tests 2 bis 4 ausführt. Ab sofort muss die Bitfolge kein Leerzeichen enthalten.
Zeit für das Zielgewinnkriterium!
Der Gewinner ist das Programm, das alle 6 Anforderungen und alle Zufälligkeitstests in einem von der Zufälligkeit nicht unterscheidbaren Maße besteht. Wenn dies mit mehreren Programmen erreicht wird, gewinnt das Programm, dessen Wiederholung am längsten dauert. Wenn dies mit mehreren Programmen erreicht wird, muss ich möglicherweise mehr Zufallstests finden, um als "Tie-Breaker" zu fungieren.
quelle
Antworten:
C 61
Ja, ich weiß, dass es kein Code-Golf ist. Dies ist offensichtlich eher ein Anti-Lösungsansatz ... aber es erfüllt sicher genug Ihre Kriterien.
Die Periodenlänge beträgt 2²⁹.
quelle
Mathematica
7853 ZeichenDie Ziffern der binären Darstellung von Pi scheinen sich so zu verhalten, als ob sie chaotisch erzeugt würden, obwohl dies nicht bewiesen ist.
Die folgende einfache Routine gibt die Binärziffern von pi, die
d
Dezimalziffern entsprechen, deterministisch als Zeichenfolge zurück :Verwendung
Wenn wir das Gegenstück von 301 Dezimalstellen von Pi anfordern, erhalten wir 1000 Binärstellen.
Da Pi eine irrationale Zahl ist, gibt es keine Periode. Es gibt jedoch praktische Einschränkungen aufgrund der verwendeten Hardware.
Test 1 Sieht für mich gut aus.
Test 2
Genauere Prüfung:
Test 3: Läuft
Ich habe eine große Anzahl von Fällen durchlaufen, um die Verteilung der Läufe systematisch zu überprüfen. In ungefähr 3 Millionen Binärziffern gab es 830.000 Läufe mit 1, 416.000 Läufen mit 2, 208.000 Läufen mit 3, 104.000 Läufen mit 4 usw.
Test 4: Übereinstimmung der ersten und zweiten Hälfte der Daten
Die Übereinstimmungen sind die 212 Fälle von 0 und 2; Die Nichtübereinstimmungen sind die 208 Fälle, in denen die Summe der entsprechenden Ziffern 1 ist.
Zeitliche Koordinierung
Die Berechnung von 3321928 Binärziffern (entsprechend 10 ^ 6 Dezimalziffern) dauert weniger als zwei Sekunden.
quelle
e
stattdessenpi
ein Byte speichern?e
chaotisch verteilt?Python, 90
g
ist der Startwert. Die Zufallsauswahl zeigt eine bemerkenswert normale Verteilung. Wiederholte Zufallsauswahl der Probenmittel ergab einen Mittelwert von0.506
und eine Standardabweichung von.0473
(Probengröße von 1000). Unglücklicherweise ist die Zufälligkeit sehr empfindlich gegenüber anfänglichem Saatgut. Der Samen im obigen Code gab mir die beste Zufälligkeit: pAKTUALISIEREN
Mal sehen, wie dieser Code den Tests des OP standhält:
Test # 1
Das ist ein bisschen subjektiv ... aber es sieht für mich ziemlich unregelmäßig aus.
Test # 2
Test Nr. 3
Läuft nach Größe:
Test Nr. 4
quelle
Haskell
7458Danke an Shiona für die Vereinfachung. Ergebnisse:
Dies ist auch ein schrecklicher Pseudo-Zufallsgenerator (ähnlich dem von von-Neuman verwendeten). Für diejenigen, die es nicht wussten
concatMap == (=<<) == flip . (>>=)
(für Listen)quelle
\x->if odd x then"1"else"0"
mitshow.(`mod`2)
.Die Frage ist im Wesentlichen gleichbedeutend mit "Implementieren einer Stream-Verschlüsselung". Also implementiere ich RC4, da es relativ einfach ist.
Ich verwende keinen Schlüssel und lasse die ersten 100000 Bits fallen, da der Beginn von RC4 ein bisschen verzerrt ist, insbesondere, weil ich den Schlüsselzeitplan übersprungen habe. Aber ich würde erwarten, dass es Ihren Test auch ohne das besteht (20 Zeichen Code sparen).
Normalerweise würde man ein volles Byte pro Zyklus ausgeben, aber in C # ist die Konvertierung in eine Binärdatei ziemlich hässlich, so dass ich einfach alles außer dem niedrigstwertigen Bit verwerfe.
Oder ohne Leerzeichen:
C #, 156 Zeichen, funktioniert im Anweisungsmodus von LinqPad. Für ein vollständiges C # -Programm fügen Sie die übliche Kesselplatte hinzu.
Wir könnten auch eingebaute Krypto-Primitive verwenden (Cheater-Lösung):
(C #, 99 Zeichen, funktioniert im Anweisungsmodus von LinqPad. Für den normalen C # -Compiler müssen Sie ein wenig Boilerplate hinzufügen.)
Die Ausgabe von kryptografischen Hash-Funktionen ist so konzipiert, dass sie nicht von zufälligen Daten unterschieden werden kann. Daher erwarte ich, dass alle Zufallstests (die härter sind, ...) bestanden werden, aber ich bin zu faul zum Testen.
quelle
C 52 Zeichen
Dies ist ein 10-Bit-LFSR, Testergebnisse:
quelle
a
sollte mit 1 beginnen (vorausgesetzt, es wird ohne Argumente aufgerufen). Auch könnte man dasa=
in die Mitte stecken , so etwas wiea=a/2^-!putchar(49-a%2)%576
(sich mit dem Algorithmus ein paar Freiheiten nehmen)a
, ich habe sie wegen "The program must not take any input from any external sources
"Salbei / Python
Dieses Programm gibt die am weitesten rechts stehenden Binärziffern aus, die jedem ausreichend hohen Exponentiationsturm der Form 3 3 3 3 gemeinsam sind . . . Für alles, was jemals möglich war, sind dies die am weitesten rechts stehenden Binärziffern von Grahams Zahl . Die Ziffernfolge ist unendlich und nicht periodisch.
Bei 1000 Stellen dauerte dies weniger als 2 Sekunden. Die Zeit nimmt jedoch viel schneller als linear in der Anzahl der Stellen zu.
Die Testergebnisse mit dem OP-Programm sind
(Weitere Informationen zu mehr als 32000 Stellen und zusätzlichen statistischen Tests finden Sie unter Sind die am weitesten rechts stehenden Stellen von G zufällig ? .)
quelle
Java,
371317Basiert auf einem 128-Bit- LFSR (Bit-Taps stammen aus der XILINX-App, Anmerkung 52 )
EDIT: Ich war nicht zufrieden mit der Verwendung von BigInteger, daher funktioniert diese Version nicht. Einige Charaktere gespeichert. Die Ausgabe könnte etwas weniger zufällig sein, da ich mir keine gute Methode für das "Säen" vorstellen könnte.
Neuer Code: Argumente: BITS_TO_PRINT
Alte Version: Argumente: SEED, BITS_TO_PRINT
Neue Version: Beispielausgabe, Bits = 100:
quelle
JavaScript - 1 ms bis 2 ms für 1000 pseudozufällige Bits (139 ms bis 153 ms für 100000 Bits)
Diese Lösung nutzt die Tatsache, dass Quadratwurzeln irrational und damit ziemlich zufällig sind. Grundsätzlich benötigt man die Quadratwurzel von 2, konvertiert sie in eine Binärzahl, wirft den führenden Teil aus, der mit der vorherigen Wurzel übereinstimmt, hängt ihn an die zufällige Zeichenfolge an und wiederholt ihn mit der nächsthöheren Zahl (oder zurück zu 2, wenn die Zahl wiederholt wird) und war mindestens 30 Bit lang) und gibt die zufällige Zeichenfolge zurück, sobald sie lang genug ist.
Ich habe die Tests noch nicht durchgearbeitet, aber ich kann mir vorstellen, dass sie gut funktionieren werden. Hier ist eine Geige, damit Sie es in Aktion sehen können. Für meine Zeit habe ich das Programm nur mehrmals ausgeführt und die schnellsten und langsamsten Werte als Bereiche verwendet.
quelle
Python
Sollte eine Periode von ungefähr 2 ^ 512 haben.
quelle
Perl, 44 Bytes
Ich weiß, dass dies kein Codegolf ist, aber ich war schon immer ein Fan von Bits niedriger Ordnung einer einfachen quadratischen Funktion, zB:
Der Zeitraum ist länger als 3 Milliarden, aber mir ist der Speicherplatz ausgegangen, um mehr zu berechnen.
quelle
$x=1/7;print substr($x*=4-4*$x,9,1)%2while 1