C Language
Zufallszahlengenerierung
Suche…
Bemerkungen
Aufgrund der Mängel von rand()
sind im Laufe der Jahre viele andere Standardimplementierungen entstanden. Darunter sind:
-
arc4random()
(verfügbar für OS X und BSD) -
random()
(verfügbar unter Linux) -
drand48()
(verfügbar für POSIX)
Generelle Zufallszahlengenerierung
Die Funktion rand()
kann verwendet werden, um einen Pseudo-Zufalls-Integer-Wert zwischen 0
und RAND_MAX
( 0
und RAND_MAX
enthalten) zu generieren.
srand(int)
wird zum srand(int)
des Pseudo-Zufallszahlengenerators verwendet. Jedes Mal, wenn rand()
demselben Samen ausgesät wird, muss dieselbe Folge von Werten erzeugt werden. Es sollte nur einmal ausgesät werden, bevor rand()
. Es sollte nicht jedes Mal wiederholt werden, wenn Sie einen neuen Stapel von Pseudo-Zufallszahlen generieren möchten.
Standardmäßig wird das Ergebnis der time(NULL)
als Startwert verwendet. Wenn für Ihren Zufallszahlengenerator eine deterministische Sequenz erforderlich ist, können Sie den Generator bei jedem Programmstart mit dem gleichen Wert starten. Dies ist im Allgemeinen nicht für den Versionscode erforderlich, ist jedoch bei Debug-Läufen hilfreich, um Fehler reproduzierbar zu machen.
Es wird empfohlen, den Generator immer zu säen, wenn er nicht ausgesät wird, verhält er sich so, als ob er mit srand(1)
ausgesät worden srand(1)
.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main(void) {
int i;
srand(time(NULL));
i = rand();
printf("Random value between [0, %d]: %d\n", RAND_MAX, i);
return 0;
}
Mögliche Ausgabe:
Random value between [0, 2147483647]: 823321433
Anmerkungen:
Der C-Standard garantiert nicht die Qualität der erzeugten Zufallssequenz. In der Vergangenheit hatten einige Implementierungen von rand()
ernsthafte Probleme bei der Verteilung und Zufälligkeit der generierten Zahlen. Die Verwendung von rand()
wird nicht für ernsthafte Zufallszahlengenerierungsanforderungen wie Kryptographie empfohlen.
Permutierter kongruentieller Generator
Hier ist ein Standalone-Zufallszahlengenerator, der nicht auf rand()
oder ähnlichen Bibliotheksfunktionen angewiesen ist.
Warum willst du so etwas? Möglicherweise vertrauen Sie nicht dem in Ihre Plattform integrierten Zufallszahlengenerator, oder Sie möchten eine reproduzierbare Zufallsquelle unabhängig von einer bestimmten Bibliotheksimplementierung.
Dieser Code ist PCG32 von pcg-random.org , ein modernes, schnelles Allzweck-RNG mit hervorragenden statistischen Eigenschaften. Es ist nicht kryptografisch sicher, verwenden Sie es also nicht für die Kryptographie.
#include <stdint.h>
/* *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));
}
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);
}
Und so nennt man es:
#include <stdio.h>
int main(void) {
pcg32_random_t rng; /* RNG state */
int i;
/* Seed the RNG */
pcg32_srandom_r(&rng, 42u, 54u);
/* Print some random 32-bit integers */
for (i = 0; i < 6; i++)
printf("0x%08x\n", pcg32_random_r(&rng));
return 0;
}
Beschränken Sie die Erzeugung auf einen bestimmten Bereich
Normalerweise ist es bei der Erzeugung von Zufallszahlen sinnvoll, Ganzzahlen innerhalb eines Bereichs oder einen p-Wert zwischen 0,0 und 1,0 zu erzeugen. Während der Modulusbetrieb verwendet werden kann, um den Startwert auf eine niedrige ganze Zahl zu reduzieren, werden die niedrigen Bits verwendet, die häufig einen kurzen Zyklus durchlaufen, was zu einer geringfügigen Verteilung der Verteilung führt, wenn N im Verhältnis zu RAND_MAX groß ist.
Das Makro
#define uniform() (rand() / (RAND_MAX + 1.0))
produziert einen p-Wert von 0,0 bis 1,0 - epsilon, also
i = (int)(uniform() * N)
setzt i
auf eine einheitliche Zufallszahl im Bereich von 0 bis N - 1.
Leider gibt es einen technischen Fehler, da RAND_MAX größer sein darf, als eine Variable vom Typ double
genau darstellen kann. Dies bedeutet, dass RAND_MAX + 1.0
zu RAND_MAX ausgewertet wird und die Funktion gelegentlich Eins zurückgibt. Dies ist jedoch unwahrscheinlich.
Xorshift Generation
Eine gute und einfache Alternative zu den fehlerhaften rand()
Prozeduren ist Xorshift , eine Klasse von Pseudozufallszahlengeneratoren, die von George Marsaglia entdeckt wurde. Der Xorshift-Generator gehört zu den schnellsten nicht-kryptographisch sicheren Zufallszahlengeneratoren. Weitere Informationen und weitere Beispiele für Implementierungen finden Sie auf der Wikipedia-Seite zu Xorshift
Beispielimplementierung
#include <stdint.h>
/* These state variables must be initialised so that they are not all zero. */
uint32_t w, x, y, z;
uint32_t xorshift128(void)
{
uint32_t t = x;
t ^= t << 11U;
t ^= t >> 8U;
x = y; y = z; z = w;
w ^= w >> 19U;
w ^= t;
return w;
}