Frage

Ich würde gerne bekommen gleichmäßige Verteilung im Bereich [0,0, 1,0)

Wenn möglich, lassen Sie die Implementierung bitte zufällige Bytes von verwenden /dev/urandom.

Es wäre auch schön, wenn Ihre Lösung wäre Thread-sicher.Wenn Sie sich nicht sicher sind, geben Sie dies bitte an.

Sehen irgendeine Lösung Ich habe darüber nachgedacht, nachdem ich andere Antworten gelesen hatte.

War es hilfreich?

Lösung 2

Das scheint ziemlich guter Weg zu sein:

unsigned short int r1, r2, r3;
// let r1, r2 and r3 hold random values
double result = ldexp(r1, -48) + ldexp(r2, -32) + ldexp(r3, -16);

Dies basiert auf NetBSDs drand48 Umsetzung.

Andere Tipps

Einfach:Ein Double hat unter der Annahme von IEEE eine Genauigkeit von 52 Bit.Generieren Sie also eine 52-Bit-Ganzzahl (oder größer) ohne Vorzeichen (z. B. durch Lesen von Bytes aus dev/urandom), konvertieren Sie sie in ein Double und dividieren Sie sie durch 2^ (Anzahl der Bits, die sie hatte).

Dies ergibt eine numerisch gleichmäßige Verteilung (da die Wahrscheinlichkeit, dass ein Wert in einem bestimmten Bereich liegt, proportional zum Bereich ist) bis zur 52. Binärstelle.

Kompliziert:Es gibt jedoch viele Double-Werte im Bereich [0,1), die mit dem oben Gesagten nicht generiert werden können.Genauer gesagt kann die Hälfte der Werte im Bereich [0,0,5) (die Werte, deren niedrigstwertiges Bit gesetzt ist) nicht auftreten.Drei Viertel der Werte im Bereich [0,0,25) (diejenigen, bei denen mindestens eines der beiden Bits gesetzt ist) können nicht auftreten usw., bis hin zu nur einem positiven Wert kleiner als 2^-51, der möglich ist. obwohl ein Doppelgänger in der Lage ist, Billionen solcher Werte darzustellen.Es kann also nicht gesagt werden, dass es über den angegebenen Bereich hinweg mit voller Präzision wirklich gleichmäßig ist.

Natürlich wollen wir nicht mit gleicher Wahrscheinlichkeit eines dieser Doppelgänger auswählen, da die resultierende Zahl dann im Durchschnitt zu klein sein wird.Wir benötigen immer noch die Wahrscheinlichkeit, dass das Ergebnis in einem bestimmten Bereich liegt, um proportional zum Bereich zu sein, aber mit einer höheren Präzision bei den Bereichen, für die das funktioniert.

ICH denken Folgendes funktioniert.Ich habe diesen Algorithmus nicht besonders untersucht oder getestet (wie Sie wahrscheinlich daran erkennen können, dass es keinen Code gibt), und ich persönlich würde ihn nicht verwenden, ohne geeignete Referenzen zu finden, die darauf hinweisen, dass er gültig ist.Aber hier geht es:

  • Beginnen Sie den Exponenten bei 52 und wählen Sie eine zufällige 52-Bit-Ganzzahl ohne Vorzeichen (unter der Annahme von 52 Bits Mantisse).
  • Wenn das höchstwertige Bit der Ganzzahl 0 ist, erhöhen Sie den Exponenten um eins, verschieben Sie die Ganzzahl um eins nach links und füllen Sie das niedrigstwertige Bit mit einem neuen Zufallsbit auf.
  • Wiederholen Sie dies, bis Sie entweder an der höchstwertigen Stelle eine 1 treffen oder der Exponent zu groß für Ihr Double (1023) wird.Oder möglicherweise 1022).
  • Wenn Sie eine 1 gefunden haben, teilen Sie Ihren Wert durch 2^Exponent.Wenn Sie nur Nullen haben, geben Sie 0 zurück (ich weiß, das ist eigentlich kein Sonderfall, aber es muss betont werden, wie sehr unwahrscheinlich eine Rückgabe von 0 ist [Bearbeiten:Tatsächlich könnte es sich um einen Sonderfall handeln – es hängt davon ab, ob Sie Denormen generieren möchten oder nicht.Wenn nicht, verwerfen Sie alles, was noch übrig ist, und geben 0 zurück, sobald Sie genügend Nullen in einer Reihe haben.In der Praxis ist dies jedoch so unwahrscheinlich, dass es vernachlässigbar ist, es sei denn, die Zufallsquelle ist nicht zufällig.

Ich weiß allerdings nicht, ob es für so ein zufälliges Double tatsächlich einen praktischen Nutzen gibt.Ihre Definition von Zufall sollte in gewissem Maße davon abhängen, wozu sie dient.Wenn Sie jedoch davon profitieren können, dass alle 52 signifikanten Bits zufällig sind, könnte dies tatsächlich hilfreich sein.

von Dateien zu lesen, ist Thread-sicher AFAIK, so mit fopen () von / dev / urandom lesen "wirklich zufällig" Bytes ergeben.

Obwohl es potentielle gotchas sein, methinks jeden Satz solchen Bytes als eine ganze Zahl zugegriffen wird, durch die maximale ganze Zahl von dieser Größe unterteilt wird einen Fließkommawert zwischen 0 und 1 ergibt mit ungefähr dieser Verteilung.

Beispiel:

FILE* f = fopen("/dev/urandom", "r");
int32_t int;
fread(&int, sizeof(int32_t), 1, f);
fclose(f);
double theRandomValue = int / (double) (2 ** 32 - 1);

Der Trick ist, dass Sie einen 54-Bit-randomizer benötigen, die Ihre Anforderungen entsprechen. Ein paar Zeilen Code mit einer Union diese 54 Bits in der Mantisse zu halten, und Sie haben Ihre Nummer. Der Trick ist, das Doppelte nicht schwimmt der Trick ist, die gewünschten randomizer.

#include <stdlib.h>
printf("%f\n", drand48());

/ dev / random:

double c;
fd = open("/dev/random", O_RDONLY);
unsigned int a, b;
read(fd, &a, sizeof(a));
read(fd, &b, sizeof(b));
if (a > b)
   c = fabs((double)b / (double)a);
else
    c = fabs((double)a / (double)b);

c ist der Zufallswert

/ dev / urandom ist nicht POSIX und ist nicht allgemein verfügbar.

Der Standard-Weg, um eine Doppel gleichmäßig in [0,1 des Erzeugen) eine ganze Zahl im Bereich von [0,2 ^ N) und Division durch 2 ^ N zu erzeugen. So Ihren Lieblings-Zufallszahlengenerator auswählen und verwenden. Für Simulationen, ist mein Mersenne Twister , da es extrem schnell ist, aber immer noch nicht gut korreliert . Eigentlich kann es dies für Sie tun, und hat sogar eine Version, die mehr Präzision für die kleineren Zahlen geben. Normalerweise geben Sie einen Samen mit zu beginnen, die für das Debuggen oder zeigen andere Ergebnisse für die Wiederholbarkeit hilft. Natürlich können Sie Ihren Code greifen eine Zufallszahl von / dev / urandom als Samen haben, wenn man nicht angegeben ist.

Für kryptographische Zwecke sollten Sie eine der Standard-Verschlüsselungsbibliotheken verwenden dort statt, wie zum Beispiel openssl ) die in der Tat wird / dev / urandom, wenn verfügbar.

Als Sicherheit einzufädeln, die meisten nicht, zumindest mit den Standard-Schnittstellen, so dass Sie eine Schicht oben bauen benötigen, oder sie nur in einem Thread verwenden. Diejenigen, die Thread-sicher sind, haben Sie einen Zustand liefern, dass sie ändern, so dass stattdessen Sie effektiv laufen mehrere nicht-interacting Zufallszahlengeneratoren, die möglicherweise nicht, was Sie suchen.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top