Se è necessario generare raddoppia, il seguente algoritmo potrebbe essere utile:
CPython generates random numbers utilizzando il seguente algoritmo (ho cambiato il nome della funzione, typedef e valori di ritorno, ma l'algoritmo rimane la stessa):
double get_random_double() {
uint32_t a = get_random_uint32_t() >> 5;
uint32_t b = get_random_uint32_t() >> 6;
return (a * 67108864.0 + b) * (1.0/9007199254740992.0);
}
La fonte di tale algoritmo è una Mersenne Twister generatore 19937 numero casuale per Takuji Nishimura e Makoto Matsumoto. Sfortunatamente il link originale menzionato nella fonte non è più disponibile per il download.
Il commento su questa funzione nel CPython osserva quanto segue:
[questa funzione] è la funzione denominata genrand_res53 nel codice originale; genera un numero casuale su [0,1) con una risoluzione di 53 bit; si noti che 9007199254740992 == 2**53
; Presumo che stiano scrivendo "/2**53
" come moltiplicando per reciproco nella speranza (probabilmente vana) che il compilatore sarà ottimizzare la divisione in fase di compilazione. 67108864
è 2**26
. Nell'effetto , a contiene 27 bit casuali spostati a sinistra 26 e b
riempimenti nei 26 bit inferiori del numeratore a 53 bit.
Il codice originale accreditato Wada Isaku per questo algoritmo, 2002/01/09
Semplificare da quel codice, se si desidera creare un float
veloce, si dovrebbe mascherare i bit di uint32_t
con (1 << FLT_MANT_DIG) - 1
e dividere per (1 << FLT_MANT_DIG)
per ottenere il corretto intervallo di [0, 1)
:
#include <stdio.h>
#include <sys/syscall.h>
#include <unistd.h>
#include <stdint.h>
#include <float.h>
int main() {
uint32_t r = 0;
float result;
for (int i = 0; i < 20; i++) {
syscall(SYS_getrandom, &r, sizeof(uint32_t), 0);
result = (float)(r & ((1 << FLT_MANT_DIG) - 1))/(1 << FLT_MANT_DIG);
printf("%f\n", result);
}
return 0;
}
Poiché si può presumere che il vostro Linux ha un compilatore C99, possiamo usare ldexpf
al posto di quella divisione:
#include <math.h>
result = ldexpf(r & ((1 << FLT_MANT_DIG) - 1), -FLT_MANT_DIG);
Per ottenere l'intervallo chiuso [0, 1]
, si può fare leggermente meno efficiente
result = ldexpf(r % (1 << FLT_MANT_DIG), -FLT_MANT_DIG);
Per generare un sacco di buona qualità numeri casuali veloci, vorrei semplicemente usare la chiamata di sistema per recuperare dati sufficienti per seminare un PRNG o CPRNG e procedere da lì.
Bene, il vostro metodo può sicuramente produrre 1. Di solito '[0,1)' è voluto Inoltre potrebbe (= volontà) hanno meno precisione rispetto IEEE doppia che ha 53 bit di mantissa. –
Piuttosto che un 'syscall()', non potresti aprire 'fopen ('/ dev/urandom', 'rb')' e leggere 4 byte? o poi metterlo in 'srand()'? – chux
Un metodo più portatile è quello di aprire '/ dev/urandom' e' read (2) 'da esso. –