Gibt es ein besseres Problem für PCG.SE als PCG, einen besseren Zufallszahlengenerator, zu implementieren ? Diese neue Veröffentlichung behauptet, einen schnellen, schwer vorhersagbaren, kleinen, statistisch optimalen Zufallszahlengenerator zu präsentieren.
Die minimale C-Implementierung umfasst nur neun Zeilen:
// *Really* minimal PCG32 code / (c) 2014 M.E. O'Neill / pcg-random.org
// Licensed under Apache License 2.0 (NO WARRANTY, etc. see website)
typedef struct { uint64_t state; uint64_t inc; } pcg32_random_t;
uint32_t pcg32_random_r(pcg32_random_t* rng)
{
uint64_t oldstate = rng->state;
// Advance internal state
rng->state = oldstate * 6364136223846793005ULL + (rng->inc|1);
// Calculate output function (XSH RR), uses old state for max ILP
uint32_t xorshifted = ((oldstate >> 18u) ^ oldstate) >> 27u;
uint32_t rot = oldstate >> 59u;
return (xorshifted >> rot) | (xorshifted << ((-rot) & 31));
}
(von: http://www.pcg-random.org/download.html )
Die Frage ist: Kannst du es besser machen?
Regeln
Schreiben Sie ein Programm oder definieren Sie eine Funktion, die PCG für vorzeichenlose 32-Bit-Ganzzahlen implementiert. Dies ist ziemlich weit gefasst: Sie können eine unendliche Folge ausdrucken, eine pcg32_random_r
Funktion und eine entsprechende Struktur definieren usw.
Sie müssen in der Lage sein, Ihren Zufallszahlengenerator entsprechend der folgenden C-Funktion zu setzen:
// pcg32_srandom(initstate, initseq)
// pcg32_srandom_r(rng, initstate, initseq):
// Seed the rng. Specified in two parts, state initializer and a
// sequence selection constant (a.k.a. stream id)
void pcg32_srandom_r(pcg32_random_t* rng, uint64_t initstate, uint64_t initseq)
{
rng->state = 0U;
rng->inc = (initseq << 1u) | 1u;
pcg32_random_r(rng);
rng->state += initstate;
pcg32_random_r(rng);
}
(aus: pcg_basic.c:37
)
Das Aufrufen des Zufallsgenerators, ohne ihn vorher zu setzen, ist undefiniertes Verhalten.
Um Ihre Übermittlung einfach zu überprüfen, stellen Sie sicher, dass die Ausgabe bei Verwendung von initstate = 42
und wie initseq = 52
folgt lautet 2380307335
:
$ tail -n 8 pcg.c
int main()
{
pcg32_random_t pcg;
pcg32_srandom_r(&pcg, 42u, 52u);
printf("%u\n", pcg32_random_r(&pcg));
return 0;
}
$ gcc pcg.c
$ ./a.out
2380307335
Wertung
Standardwertung. In Bytes gemessen. Das Niedrigste ist das Beste. Bei Gleichstand gewinnt die frühere Einreichung. Es gelten Standardlücken .
Probelösung
Kompiliert unter gcc -W -Wall
sauber (Version 4.8.2).
Vergleichen Sie Ihre Eingabe damit, um sicherzustellen, dass Sie die gleiche Reihenfolge erhalten.
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
typedef struct { uint64_t state; uint64_t inc; } pcg32_random_t;
uint32_t pcg32_random_r(pcg32_random_t* rng)
{
uint64_t oldstate = rng->state;
// Advance internal state
rng->state = oldstate * 6364136223846793005ULL + (rng->inc|1);
// Calculate output function (XSH RR), uses old state for max ILP
uint32_t xorshifted = ((oldstate >> 18u) ^ oldstate) >> 27u;
uint32_t rot = oldstate >> 59u;
return (xorshifted >> rot) | (xorshifted << ((-rot) & 31));
}
void pcg32_srandom_r(pcg32_random_t* rng, uint64_t initstate, uint64_t initseq)
{
rng->state = 0U;
rng->inc = (initseq << 1u) | 1u;
pcg32_random_r(rng);
rng->state += initstate;
pcg32_random_r(rng);
}
int main()
{
size_t i;
pcg32_random_t pcg;
pcg32_srandom_r(&pcg, 42u, 52u);
for (i = 0; i < 16; i++)
{
printf("%u\n", pcg32_random_r(&pcg));
}
return 0;
}
Sequenz:
2380307335
948027835
187788573
3952545547
2315139320
3279422313
2401519167
2248674523
3148099331
3383824018
2720691756
2668542805
2457340157
3945009091
1614694131
4292140870
Antworten:
CJam,
1091071049891 BytesDabei werden einige Zeichen außerhalb des ASCII-Bereichs verwendet, jedoch alle innerhalb des erweiterten ASCII-Bereichs. Daher zähle ich jedes Zeichen als Byte (anstatt als UTF-8).
Dies ist im Grunde ein genauer Port des C-Codes.
Die Startfunktion ist ein Block, in dem gespeichert ist
S
, und die Zufallsfunktion ist ein Block, in dem gespeichert istR
.S
erwartetinitstate
undinitseq
auf den Stapel und sät das PRNG.R
erwartet nichts auf dem Stapel und belässt die nächste Zufallszahl darauf.Da das Aufrufen
R
vor dem AufrufenS
undefiniertes Verhalten ist, definiere ich es tatsächlichR
innerhalb vonS
. Bis Sie also den Startblock verwenden,R
ist es nur eine leere Zeichenfolge und unbrauchbar.Das
state
ist in VariableA
und dasinc
ist in gespeichertB
.Erläuterung:
Und hier ist das Äquivalent des Testgeschirrs im OP:
die genau die gleichen Zahlen druckt.
Teste es hier. Stack Exchange entfernt die beiden nicht druckbaren Zeichen, sodass es nicht funktioniert, wenn Sie das obige Snippet kopieren. Kopieren Sie stattdessen den Code vom Zeichenzähler .
quelle
C 195
Ich dachte, jemand sollte eine kompaktere C-Implementierung veröffentlichen, auch wenn es keine Gewinnchance gibt. Die dritte Zeile enthält zwei Funktionen:
r()
(äquivalent zupcg32_random_r()
) unds()
(äquivalent zupcg32_srandom_r()
). Die letzte Zeile ist diemain()
Funktion, die von der Zeichenanzahl ausgeschlossen ist.Obwohl der Compiler sich beschwert, sollte dies auf einem 64-Bit-Computer ordnungsgemäß funktionieren. Auf einem 32-Bit - Rechnern finden Sie weitere 5 Bytes zu ändern hinzufügen müssen ,
#define L long
um#define L long long
( wie in dieser ideone Demo ).quelle
srandom
Funktion Teil Ihrer Einreichung ist und in die Zeichenanzahl aufgenommen werden sollte. (Schließlich könnten Sie sich vielleicht eine clevere Möglichkeit vorstellen, dies zu optimieren.) Meiner Meinung nach würde dies Ihre aktuelle Punktzahl auf 197 bringen.Julia,
218199191 BytesDas Umbenennen von Datentypen und ein paar andere kleine Tricks haben mir geholfen, die Länge um zusätzliche 19 Bytes zu reduzieren. Hauptsächlich durch Weglassen von zwei :: Int64-Typzuweisungen .
Erklärung der Namen (mit entsprechenden Namen in der ungolfed Version unten):
Initialisieren Sie den Startwert mit Status 42 und Sequenz 52. Aufgrund des kleineren Programms müssen Sie den Datentyp jetzt explizit während der Initialisierung angeben (ca. 14 Byte Code gespeichert). Sie können die explizite Typzuweisung auf 64-Bit-Systemen weglassen:
Produziere den ersten Satz von Zufallszahlen:
Ergebnis:
Ich war wirklich überrascht, dass selbst meine ungolfed Julia-Version darunter so viel kleiner ist (543 Bytes) als die Musterlösung in C (958 Bytes).
Ungolfed-Version, 543 Bytes
Sie initialisieren den Startwert (Anfangszustand = 42, Anfangssequenz = 52) mit:
Dann können Sie Zufallszahlen erstellen mit:
Hier ist das Ergebnis eines Testskripts:
Da ich ein abgründiger Programmierer bin, habe ich fast einen Tag gebraucht, um es zum Laufen zu bringen. Das letzte Mal, dass ich versucht habe, etwas in C (eigentlich C ++) zu programmieren, war fast 18 Jahre her, aber eine Menge Google-Fu hat mir schließlich geholfen, eine funktionierende Julia-Version zu erstellen. Ich muss sagen, ich habe in nur wenigen Tagen auf Codegolf viel gelernt. Jetzt kann ich anfangen, an einer Piet-Version zu arbeiten. Das wird eine Menge Arbeit, aber ich möchte wirklich, wirklich einen (guten) Zufallsgenerator für Piet;)
quelle