23
23
#include "stdlib/random/base.h"
24
24
#include "stdlib/random/base/minstd.h"
25
25
26
+ // Forward declarations:
27
+ static inline int8_t next ( struct BasePRNGObject * obj , uint64_t * out );
28
+ static inline int8_t normalized ( struct BasePRNGObject * obj , double * out );
29
+
26
30
// Define the LCG multiplier:
27
31
static const uint32_t A = 16807 ;
28
32
@@ -32,57 +36,79 @@ static const uint32_t MAX_INT32 = 0x7fffffff;
32
36
// Define the normalization constant:
33
37
static const double NORMALIZATION_CONSTANT = 2147483646.0 ; // MAX_INT32 - 1
34
38
39
+ /**
40
+ * MINSTD PRNG.
41
+ *
42
+ * @private
43
+ */
44
+ static const struct BasePRNG minstd_prng = {
45
+ "minstd" , // name
46
+ (uint64_t )1 , // min
47
+ (uint64_t )MAX_INT32 - 1 , // max: (2^{31}-1) - 1
48
+ 0.0 , // min (normalized)
49
+ (MAX_INT32 - 2 ) / NORMALIZATION_CONSTANT , // max (normalized): (MIN-1)/MAX
50
+ sizeof ( stdlib_base_minstd_prng_state_t ), // state_size
51
+ & next , // next()
52
+ & normalized // normalized()
53
+ };
54
+
35
55
/**
36
56
* Returns a pseudorandom integer.
37
57
*
58
+ * ## Notes
59
+ *
60
+ * - The function returns `-1` if unable to generate a pseudorandom integer and `0` otherwise.
61
+ *
38
62
* @private
39
- * @param vstate PRNG state
40
- * @return pseudorandom integer
63
+ * @param obj PRNG object
64
+ * @param out output address
65
+ * @return status code
41
66
*/
42
- static inline uint64_t next ( void * vstate ) {
43
- // Cast the "void state" argument to a MINSTD state object:
44
- stdlib_base_minstd_prng_state_t * obj = (stdlib_base_minstd_prng_state_t * )( vstate );
67
+ static inline int8_t next ( struct BasePRNGObject * obj , uint64_t * out ) {
68
+ if ( obj == NULL || obj -> prng != & minstd_prng ) {
69
+ return -1 ;
70
+ }
71
+ // Retrieve the MINSTD state object:
72
+ stdlib_base_minstd_prng_state_t * so = (stdlib_base_minstd_prng_state_t * )( obj -> state );
45
73
46
74
// Retrieve the current state:
47
- uint32_t state = obj -> state ;
75
+ uint32_t state = so -> state ;
48
76
49
77
// Explicitly cast to 64-bit to handle integer overflow:
50
78
state = (A * (uint64_t )state ) % MAX_INT32 ;
51
79
52
80
// Update the PRNG state:
53
- obj -> state = state ;
81
+ so -> state = state ;
54
82
55
- // Return the generated value:
56
- return (uint64_t )state ;
83
+ // Set the output value:
84
+ * out = (uint64_t )state ;
85
+
86
+ return 0 ;
57
87
}
58
88
59
89
/**
60
90
* Returns a pseudorandom double-precision floating-point number on the interval `[0,1)`.
61
91
*
62
- * @private
63
- * @param vstate PRNG state
64
- * @return pseudorandom number
65
- */
66
- static inline double normalized ( void * vstate ) {
67
- double state = (double )next ( vstate );
68
- return (state - 1.0 ) / NORMALIZATION_CONSTANT ;
69
- }
70
-
71
- /**
72
- * MINSTD PRNG.
92
+ * ## Notes
93
+ *
94
+ * - The function returns `-1` if unable to generate a pseudorandom number and `0` otherwise.
73
95
*
74
96
* @private
97
+ * @param obj PRNG object
98
+ * @param out output address
99
+ * @return status code
75
100
*/
76
- static const struct BasePRNG minstd_prng = {
77
- "minstd" , // name
78
- (uint64_t )1 , // min
79
- (uint64_t )MAX_INT32 - 1 , // max: (2^{31}-1) - 1
80
- 0.0 , // min (normalized)
81
- (MAX_INT32 - 2 ) / NORMALIZATION_CONSTANT , // max (normalized): (MIN-1)/MAX
82
- sizeof ( stdlib_base_minstd_prng_state_t ), // state_size
83
- & next , // next()
84
- & normalized // normalized()
85
- };
101
+ static inline int8_t normalized ( struct BasePRNGObject * obj , double * out ) {
102
+ uint64_t state ;
103
+ int8_t status = next ( obj , & state );
104
+ if ( status != 0 ) {
105
+ return -1 ;
106
+ }
107
+ // Note: casting `state` to a double here is fine, as `state` will never exceed the maximum "safe" double-precision floating-point number:
108
+ * out = ((double )state - 1.0 ) / NORMALIZATION_CONSTANT ;
109
+
110
+ return 0 ;
111
+ }
86
112
87
113
/**
88
114
* Returns a pointer to a dynamically allocated MINSTD PRNG.
@@ -109,12 +135,20 @@ static const struct BasePRNG minstd_prng = {
109
135
* exit( 1 );
110
136
* }
111
137
*
112
- * uint64_t r = obj->prng->next( obj->state );
138
+ * uint64_t r;
139
+ * int8_t status = obj->prng->next( obj, &r );
140
+ * if ( status != 0 ) {
141
+ * fprintf( stderr, "Unexpected result.\n" );
142
+ * exit( 1 );
143
+ * }
144
+ *
145
+ * // ...
146
+ *
147
+ * status = obj->prng->next( obj, &r );
113
148
*
114
149
* // ...
115
150
*
116
- * r = obj->prng->next( obj->state );
117
- * r = obj->prng->next( obj->state );
151
+ * status = obj->prng->next( obj, &r );
118
152
*
119
153
* // ...
120
154
*
@@ -171,12 +205,20 @@ struct BasePRNGObject * stdlib_base_minstd_prng_allocate( const int32_t seed ) {
171
205
* exit( 1 );
172
206
* }
173
207
*
174
- * uint64_t r = obj->prng->next( obj->state );
208
+ * uint64_t r;
209
+ * int8_t status = obj->prng->next( obj, &r );
210
+ * if ( status != 0 ) {
211
+ * fprintf( stderr, "Unexpected result.\n" );
212
+ * exit( 1 );
213
+ * }
214
+ *
215
+ * // ...
216
+ *
217
+ * status = obj->prng->next( obj, &r );
175
218
*
176
219
* // ...
177
220
*
178
- * r = obj->prng->next( obj->state );
179
- * r = obj->prng->next( obj->state );
221
+ * status = obj->prng->next( obj, &r );
180
222
*
181
223
* // ...
182
224
*
@@ -314,12 +356,20 @@ void * stdlib_base_minstd_prng_state( const struct BasePRNGObject *obj ) {
314
356
* exit( 1 );
315
357
* }
316
358
*
317
- * uint64_t r = obj->prng->next( obj->state );
359
+ * uint64_t r;
360
+ * int8_t status = obj->prng->next( obj, &r );
361
+ * if ( status != 0 ) {
362
+ * fprintf( stderr, "Unexpected result.\n" );
363
+ * exit( 1 );
364
+ * }
365
+ *
366
+ * // ...
367
+ *
368
+ * status = obj->prng->next( obj, &r );
318
369
*
319
370
* // ...
320
371
*
321
- * r = obj->prng->next( obj->state );
322
- * r = obj->prng->next( obj->state );
372
+ * status = obj->prng->next( obj, &r );
323
373
*
324
374
* // ...
325
375
*
@@ -332,22 +382,28 @@ void * stdlib_base_minstd_prng_state( const struct BasePRNGObject *obj ) {
332
382
*
333
383
* // ...
334
384
*
335
- * r = obj->prng->next( obj->state );
336
- * r = obj->prng->next( obj->state );
385
+ * status = obj->prng->next( obj, &r );
386
+ *
387
+ * // ...
388
+ *
389
+ * status = obj->prng->next( obj, &r );
337
390
*
338
391
* // ...
339
392
*
340
393
* // Reset the PRNG to a previous state...
341
- * int8_t status = stdlib_base_minstd_prng_set( obj, state );
394
+ * status = stdlib_base_minstd_prng_set( obj, state );
342
395
* if ( status != 0 ) {
343
396
* fprintf( stderr, "Error encountered when attempting to set PRNG state.\n" );
344
397
* exit( 1 );
345
398
* }
346
399
*
347
400
* // ...
348
401
*
349
- * r = obj->prng->next( obj->state );
350
- * r = obj->prng->next( obj->state );
402
+ * status = obj->prng->next( obj, &r );
403
+ *
404
+ * // ...
405
+ *
406
+ * status = obj->prng->next( obj, &r );
351
407
*
352
408
* // ...
353
409
*
0 commit comments