@@ -28,28 +28,31 @@ static inline int8_t normalized( struct BasePRNGObject *obj, double *out );
2828static inline void pcg32_free ( struct BasePRNGObject * obj );
2929
3030// Define the LCG multiplier:
31- static const uint32_t A = 16807 ;
31+ static const uint64_t MULTIPLIER = 0x5851F42D4C957F2DULL ;
3232
33- // Define the maximum signed 32-bit integer: 2147483647 => 0x7fffffff => 01111111111111111111111111111111
34- static const uint32_t MAX_INT32 = 0x7fffffff ;
33+ // Define the LCG increment: #TODO: Make user definable like seed
34+ static const uint64_t INCREMENT = 0xBEEF00000000DEADULL ;
35+
36+ // Define the maximum unsigned 32-bit integer: 4294967295 => 0xffffffff => 11111111111111111111111111111111
37+ static const uint32_t MAX_UINT32 = 0xffffffff ;
3538
3639// Define the normalization constant:
37- static const double NORMALIZATION_CONSTANT = 2147483646.0 ; // MAX_INT32 - 1
40+ static const double NORMALIZATION_CONSTANT = MAX_UINT32 + 1.0 ;
3841
3942/**
4043* PCG32 PRNG.
4144*
4245*/
4346static const struct BasePRNG pcg32_prng = {
44- "pcg32" , // name
45- (uint64_t )1 , // min
46- (uint64_t )MAX_INT32 - 1 , // max: ( 2^{31}-1) - 1
47- 0.0 , // min (normalized)
48- ( MAX_INT32 - 2 ) / NORMALIZATION_CONSTANT , // max (normalized): (MAX-1)/MAX
49- sizeof ( stdlib_base_random_pcg32_state_t ), // state_size
50- & next , // next()
51- & normalized , // normalized()
52- & pcg32_free // free()
47+ "pcg32" , // name
48+ (uint64_t )0 , // min
49+ (uint64_t )MAX_UINT32 , // max: 2^{32}- 1
50+ 0.0 , // min (normalized)
51+ MAX_UINT32 / NORMALIZATION_CONSTANT , // max (normalized): (MAX-1)/MAX
52+ sizeof ( stdlib_base_random_pcg32_state_t ), // state_size
53+ & next , // next()
54+ & normalized , // normalized()
55+ & pcg32_free // free()
5356};
5457
5558/**
@@ -64,23 +67,30 @@ static const struct BasePRNG pcg32_prng = {
6467* @return status code
6568*/
6669static inline int8_t next ( struct BasePRNGObject * obj , uint64_t * out ) {
70+ uint32_t xorshifted ;
71+ uint64_t oldstate ;
72+ uint32_t output ;
73+ uint32_t rot ;
74+
6775 if ( obj == NULL || obj -> prng != & pcg32_prng ) {
6876 return -1 ;
6977 }
7078 // Retrieve the state object:
7179 stdlib_base_random_pcg32_state_t * so = (stdlib_base_random_pcg32_state_t * )( obj -> state );
7280
7381 // Retrieve the current state:
74- uint32_t state = so -> state ;
75-
76- // Explicitly cast to 64-bit to handle integer overflow:
77- state = (A * (uint64_t )state ) % MAX_INT32 ;
82+ oldstate = so -> state ;
7883
7984 // Update the PRNG state:
80- so -> state = state ;
85+ so -> state = oldstate * MULTIPLIER + INCREMENT ;
86+
87+ // Apply output permutaion (XSH-RR)
88+ xorshifted = ( ( oldstate >> 18 ) ^ oldstate ) >> 27 ;
89+ rot = oldstate >> 59 ;
90+ output = ( xorshifted >> rot ) | ( xorshifted << ( - rot & 31 ) );
8191
8292 // Set the output value:
83- * out = (uint64_t )state ;
93+ * out = (uint64_t )output ;
8494
8595 return 0 ;
8696}
@@ -97,13 +107,13 @@ static inline int8_t next( struct BasePRNGObject *obj, uint64_t *out ) {
97107* @return status code
98108*/
99109static inline int8_t normalized ( struct BasePRNGObject * obj , double * out ) {
100- uint64_t state ;
101- int8_t status = next ( obj , & state );
110+ uint64_t output ;
111+ int8_t status = next ( obj , & output );
102112 if ( status != 0 ) {
103113 return -1 ;
104114 }
105- // Note: casting `state ` to a double here is fine, as `state ` will never exceed the maximum "safe" double-precision floating-point number:
106- * out = (( double )state - 1.0 ) / NORMALIZATION_CONSTANT ;
115+ // Note: casting `output ` to a double here is fine, as `output ` will never exceed the maximum "safe" double-precision floating-point number:
116+ * out = (double )output / NORMALIZATION_CONSTANT ;
107117
108118 return 0 ;
109119}
@@ -127,7 +137,7 @@ static inline void pcg32_free( struct BasePRNGObject *obj ) {
127137* ## Notes
128138*
129139* - The user is responsible for freeing the allocated memory.
130- * - A provided `seed` is mapped to the interval `[1,2147483646 ]`.
140+ * - A provided `seed` is mapped to the interval `[0,18446744073709551615 ]`.
131141*
132142* @param seed PRNG seed
133143* @return pointer to a dynamically allocated PRNG or, if unable to allocate memory, a null pointer
@@ -166,8 +176,8 @@ static inline void pcg32_free( struct BasePRNGObject *obj ) {
166176* // Free allocated memory:
167177* stdlib_base_random_pcg32_free( obj );
168178*/
169- struct BasePRNGObject * stdlib_base_random_pcg32_allocate ( const int32_t seed ) {
170- uint32_t iseed ;
179+ struct BasePRNGObject * stdlib_base_random_pcg32_allocate ( const uint64_t seed ) {
180+ uint64_t output ;
171181
172182 struct BasePRNGObject * obj = malloc ( sizeof ( struct BasePRNGObject ) );
173183 if ( obj == NULL ) {
@@ -179,20 +189,17 @@ struct BasePRNGObject * stdlib_base_random_pcg32_allocate( const int32_t seed )
179189 return NULL ;
180190 }
181191 // Ensure that the provided seed is within allowed bounds...
182- if ( seed == 0 ) {
183- iseed = 1 ;
184- } else if ( seed == MAX_INT32 ) {
185- iseed = MAX_INT32 - 1 ;
186- } else if ( seed < 0 ) {
187- iseed = - seed ;
188- } else {
189- iseed = seed ;
190- }
191- state -> seed = (uint32_t )iseed ;
192- state -> state = (uint32_t )iseed ;
192+ // No need to check, any unsigned 64-bit integer is a valid seed
193193
194- obj -> prng = & pcg32_prng ;
194+ state -> seed = seed ;
195+ state -> state = 0 ;
195196 obj -> state = state ;
197+ obj -> prng = & pcg32_prng ;
198+
199+ // Initialize the internal PRNG state:
200+ next ( obj , & output );
201+ state -> state += seed ;
202+ next ( obj , & output );
196203
197204 return obj ;
198205}
@@ -268,7 +275,7 @@ void stdlib_base_random_pcg32_free( struct BasePRNGObject *obj ) {
268275* exit( 1 );
269276* }
270277*
271- * int32_t seed;
278+ * uint64_t seed;
272279* int8_t status = stdlib_base_random_pcg32_seed( obj, &seed );
273280* if ( status != 0 ) {
274281* fprintf( stderr, "Error encountered when attempting to retrieve the PRNG seed.\n" );
@@ -280,15 +287,15 @@ void stdlib_base_random_pcg32_free( struct BasePRNGObject *obj ) {
280287* // Free allocated memory:
281288* stdlib_base_random_pcg32_free( obj );
282289*/
283- int8_t stdlib_base_random_pcg32_seed ( const struct BasePRNGObject * obj , int32_t * out ) {
290+ int8_t stdlib_base_random_pcg32_seed ( const struct BasePRNGObject * obj , uint64_t * out ) {
284291 if ( obj == NULL || obj -> prng != & pcg32_prng ) {
285292 return -1 ;
286293 }
287294 // Retrieve the PCG32 state object:
288295 const stdlib_base_random_pcg32_state_t * state = (stdlib_base_random_pcg32_state_t * )( obj -> state );
289296
290297 // Set the output value:
291- * out = (int32_t )( state -> seed );
298+ * out = (uint64_t )( state -> seed );
292299
293300 return 0 ;
294301}
0 commit comments