Skip to content

Commit 16f62aa

Browse files
feat: add C implementation for pcg32
--- type: pre_commit_static_analysis_report description: Results of running static analysis checks when committing changes. report: - task: lint_filenames status: passed - task: lint_editorconfig status: passed - task: lint_markdown status: na - task: lint_package_json status: na - task: lint_repl_help status: na - task: lint_javascript_src status: passed - task: lint_javascript_cli status: na - task: lint_javascript_examples status: na - task: lint_javascript_tests status: na - task: lint_javascript_benchmarks status: na - task: lint_python status: na - task: lint_r status: na - task: lint_c_src status: passed - task: lint_c_examples status: na - task: lint_c_benchmarks status: na - task: lint_c_tests_fixtures status: na - task: lint_shell status: na - task: lint_typescript_declarations status: na - task: lint_typescript_tests status: na - task: lint_license_headers status: passed ---
1 parent 9a6d63f commit 16f62aa

File tree

3 files changed

+54
-47
lines changed

3 files changed

+54
-47
lines changed

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,14 +33,14 @@ extern "C" {
3333
* Declare an opaque type definition for the PRNG state.
3434
*/
3535
typedef struct {
36-
uint32_t seed;
37-
uint32_t state;
36+
uint64_t seed;
37+
uint64_t state;
3838
} stdlib_base_random_pcg32_state_t;
3939

4040
/**
4141
* Returns a pointer to a dynamically allocated PRNG.
4242
*/
43-
struct BasePRNGObject * stdlib_base_random_pcg32_allocate( const int32_t seed );
43+
struct BasePRNGObject * stdlib_base_random_pcg32_allocate( const int64_t seed );
4444

4545
/**
4646
* Frees a PRNG's allocated memory.
@@ -50,7 +50,7 @@ void stdlib_base_random_pcg32_free( struct BasePRNGObject *obj );
5050
/**
5151
* Returns a PRNG seed.
5252
*/
53-
int8_t stdlib_base_random_pcg32_seed( const struct BasePRNGObject *obj, int32_t *out );
53+
int8_t stdlib_base_random_pcg32_seed( const struct BasePRNGObject *obj, int64_t *out );
5454

5555
/**
5656
* Returns a copy of the current PRNG state.

lib/node_modules/@stdlib/random/base/pcg32/lib/factory.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,10 @@ var randuint32 = require( './rand_uint32.js' );
4646
var NORMALIZATION_CONSTANT = UINT32_MAX + 1;
4747
var MAX_SEED = UINT32_MAX >>> 0; // asm type annotation
4848

49-
// Define the LCG multiplier
49+
// Define the LCG multiplier:
5050
var MULTIPLIER = [ 0x5851F42D >>> 0, 0x4C957F2D >>> 0 ]; // asm type annotation
5151

52-
// Define the LCG increment which controls the stream. #TODO: Make user definable like seed
52+
// Define the LCG increment: #TODO: Make user definable like seed
5353
var INCREMENT = [ 0xBEEF0000 >>> 0, 0x0000DEAD >>> 0 ]; // asm type annotation
5454

5555
// Define the size of state as a multiple of 32-bits

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

Lines changed: 48 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -28,28 +28,31 @@ static inline int8_t normalized( struct BasePRNGObject *obj, double *out );
2828
static 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
*/
4346
static 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
*/
6669
static 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
*/
99109
static 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

Comments
 (0)