Skip to content

Commit d86cba9

Browse files
committed
Refactor functions for generating pseudorandom numbers
1 parent 6a41a50 commit d86cba9

File tree

4 files changed

+127
-54
lines changed

4 files changed

+127
-54
lines changed

lib/node_modules/@stdlib/random/base/include/stdlib/random/base.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@
2121

2222
#include <stdint.h>
2323

24+
// Forward declaration.
25+
struct BasePRNGObject;
26+
2427
/**
2528
* Base PRNG structure.
2629
*/
@@ -44,10 +47,10 @@ struct BasePRNG {
4447
const size_t state_size;
4548

4649
// Define a pointer to a function for returning the next generated value:
47-
uint64_t (* const next)( void *BasePRNGObject );
50+
int8_t (* const next)( struct BasePRNGObject *obj, uint64_t *out );
4851

4952
// Define a pointer to a function for returning the next generated value on the interval `[0,1)`:
50-
double (* const normalized)( void *BasePRNGObject );
53+
int8_t (* const normalized)( struct BasePRNGObject *obj, double *out );
5154
};
5255

5356
/**

lib/node_modules/@stdlib/random/base/minstd/benchmark/c/benchmark.c

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ double benchmark1() {
128128
*/
129129
double benchmark2() {
130130
double elapsed;
131+
int8_t status;
131132
uint64_t max;
132133
uint64_t v;
133134
double t;
@@ -142,15 +143,15 @@ double benchmark2() {
142143

143144
t = tic();
144145
for ( i = 0; i < ITERATIONS; i++ ) {
145-
v = obj->prng->next( obj->state );
146-
if ( v > max ) {
146+
status = obj->prng->next( obj, &v );
147+
if ( status != 0 || v > max ) {
147148
printf( "unexpected result\n" );
148149
break;
149150
}
150151
}
151152
elapsed = tic() - t;
152153

153-
if ( v > max ) {
154+
if ( status != 0 || v > max ) {
154155
printf( "unexpected result\n" );
155156
}
156157
stdlib_base_minstd_prng_free( obj );
@@ -165,6 +166,7 @@ double benchmark2() {
165166
*/
166167
double benchmark3() {
167168
double elapsed;
169+
int8_t status;
168170
double v;
169171
double t;
170172
int i;
@@ -177,15 +179,15 @@ double benchmark3() {
177179

178180
t = tic();
179181
for ( i = 0; i < ITERATIONS; i++ ) {
180-
v = obj->prng->normalized( obj->state );
181-
if ( v != v ) {
182+
status = obj->prng->normalized( obj, &v );
183+
if ( status != 0 || v != v ) {
182184
printf( "unexpected result\n" );
183185
break;
184186
}
185187
}
186188
elapsed = tic() - t;
187189

188-
if ( v != v ) {
190+
if ( status != 0 || v != v ) {
189191
printf( "unexpected result\n" );
190192
}
191193
stdlib_base_minstd_prng_free( obj );

lib/node_modules/@stdlib/random/base/minstd/examples/c/example.c

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,9 @@
2424
int main() {
2525
int8_t status;
2626
int32_t seed;
27+
uint64_t v;
2728
int32_t i;
29+
double d;
2830

2931
// Create a PRNG...
3032
struct BasePRNGObject *obj = stdlib_base_minstd_prng_allocate( 12345 );
@@ -46,7 +48,12 @@ int main() {
4648

4749
printf( "\nPseudorandom integers...\n" );
4850
for ( i = 0; i < 10; i++ ) {
49-
printf( "%llu\n", obj->prng->next( obj->state ) );
51+
status = obj->prng->next( obj, &v );
52+
if ( status != 0 ) {
53+
printf( "Unexpected result.\n" );
54+
exit( 1 );
55+
}
56+
printf( "%llu\n", v );
5057
}
5158

5259
printf( "\n" );
@@ -55,7 +62,12 @@ int main() {
5562

5663
printf( "\nPseudorandom doubles...\n" );
5764
for ( i = 0; i < 10; i++ ) {
58-
printf( "%0.16f\n", obj->prng->normalized( obj->state ) );
65+
status = obj->prng->normalized( obj, &d );
66+
if ( status != 0 ) {
67+
printf( "Unexpected result.\n" );
68+
exit( 1 );
69+
}
70+
printf( "%0.16f\n", d );
5971
}
6072

6173
stdlib_base_minstd_prng_free( obj );

lib/node_modules/@stdlib/random/base/minstd/src/main.c

Lines changed: 100 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@
2323
#include "stdlib/random/base.h"
2424
#include "stdlib/random/base/minstd.h"
2525

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+
2630
// Define the LCG multiplier:
2731
static const uint32_t A = 16807;
2832

@@ -32,57 +36,79 @@ static const uint32_t MAX_INT32 = 0x7fffffff;
3236
// Define the normalization constant:
3337
static const double NORMALIZATION_CONSTANT = 2147483646.0; // MAX_INT32 - 1
3438

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+
3555
/**
3656
* Returns a pseudorandom integer.
3757
*
58+
* ## Notes
59+
*
60+
* - The function returns `-1` if unable to generate a pseudorandom integer and `0` otherwise.
61+
*
3862
* @private
39-
* @param vstate PRNG state
40-
* @return pseudorandom integer
63+
* @param obj PRNG object
64+
* @param out output address
65+
* @return status code
4166
*/
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 );
4573

4674
// Retrieve the current state:
47-
uint32_t state = obj->state;
75+
uint32_t state = so->state;
4876

4977
// Explicitly cast to 64-bit to handle integer overflow:
5078
state = (A*(uint64_t)state) % MAX_INT32;
5179

5280
// Update the PRNG state:
53-
obj->state = state;
81+
so->state = state;
5482

55-
// Return the generated value:
56-
return (uint64_t)state;
83+
// Set the output value:
84+
*out = (uint64_t)state;
85+
86+
return 0;
5787
}
5888

5989
/**
6090
* Returns a pseudorandom double-precision floating-point number on the interval `[0,1)`.
6191
*
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.
7395
*
7496
* @private
97+
* @param obj PRNG object
98+
* @param out output address
99+
* @return status code
75100
*/
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+
}
86112

87113
/**
88114
* Returns a pointer to a dynamically allocated MINSTD PRNG.
@@ -109,12 +135,20 @@ static const struct BasePRNG minstd_prng = {
109135
* exit( 1 );
110136
* }
111137
*
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 );
113148
*
114149
* // ...
115150
*
116-
* r = obj->prng->next( obj->state );
117-
* r = obj->prng->next( obj->state );
151+
* status = obj->prng->next( obj, &r );
118152
*
119153
* // ...
120154
*
@@ -171,12 +205,20 @@ struct BasePRNGObject * stdlib_base_minstd_prng_allocate( const int32_t seed ) {
171205
* exit( 1 );
172206
* }
173207
*
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 );
175218
*
176219
* // ...
177220
*
178-
* r = obj->prng->next( obj->state );
179-
* r = obj->prng->next( obj->state );
221+
* status = obj->prng->next( obj, &r );
180222
*
181223
* // ...
182224
*
@@ -314,12 +356,20 @@ void * stdlib_base_minstd_prng_state( const struct BasePRNGObject *obj ) {
314356
* exit( 1 );
315357
* }
316358
*
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 );
318369
*
319370
* // ...
320371
*
321-
* r = obj->prng->next( obj->state );
322-
* r = obj->prng->next( obj->state );
372+
* status = obj->prng->next( obj, &r );
323373
*
324374
* // ...
325375
*
@@ -332,22 +382,28 @@ void * stdlib_base_minstd_prng_state( const struct BasePRNGObject *obj ) {
332382
*
333383
* // ...
334384
*
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 );
337390
*
338391
* // ...
339392
*
340393
* // 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 );
342395
* if ( status != 0 ) {
343396
* fprintf( stderr, "Error encountered when attempting to set PRNG state.\n" );
344397
* exit( 1 );
345398
* }
346399
*
347400
* // ...
348401
*
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 );
351407
*
352408
* // ...
353409
*

0 commit comments

Comments
 (0)