Skip to content

Commit 3386039

Browse files
feat(random): implement xorshift generator
--- 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: passed - 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: passed - 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: passed - task: lint_typescript_tests status: na - task: lint_license_headers status: passed ---
1 parent 001eadf commit 3386039

File tree

7 files changed

+153
-158
lines changed

7 files changed

+153
-158
lines changed

lib/node_modules/@stdlib/random/base/xorshift/README.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ limitations under the License.
1818
1919
-->
2020

21-
# MINSTD
21+
# XORSHIFT
2222

2323
> A linear congruential pseudorandom number generator ([LCG][lcg]) based on Park and Miller.
2424
@@ -70,7 +70,7 @@ var rand = xorshift.factory({
7070
});
7171

7272
var r = rand();
73-
// returns 20739838
73+
// returns 332584831
7474
```
7575

7676
or, for arbitrary length seeds, an array-like `object` containing signed 32-bit integers
@@ -83,7 +83,7 @@ var rand = xorshift.factory({
8383
});
8484

8585
var r = rand();
86-
// returns 20739838
86+
// returns 332584831
8787
```
8888

8989
To return a generator having a specific initial state, set the generator `state` option.
@@ -130,7 +130,7 @@ Maximum possible value.
130130

131131
```javascript
132132
var max = xorshift.MAX;
133-
// returns 2147483646
133+
// returns 4294967295
134134
```
135135

136136
#### xorshift.seed
@@ -178,7 +178,7 @@ r = xorshift();
178178

179179
// Get the current state:
180180
var state = xorshift.state;
181-
// returns <Int32Array>
181+
// returns <Uint32Array>
182182

183183
r = xorshift();
184184
// returns <number>

lib/node_modules/@stdlib/random/base/xorshift/docs/types/index.d.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,12 @@ interface Options {
2929
/**
3030
* Pseudorandom number generator seed.
3131
*/
32-
seed?: random.PRNGSeedMINSTD;
32+
seed?: random.PRNGSeedXORSHIFT;
3333

3434
/**
3535
* Pseudorandom number generator state.
3636
*/
37-
state?: random.PRNGStateMINSTD;
37+
state?: random.PRNGStateXORSHIFT;
3838

3939
/**
4040
* Specifies whether to copy a provided pseudorandom number generator state.
@@ -64,7 +64,7 @@ interface PRNG {
6464
/**
6565
* PRNG seed.
6666
*/
67-
readonly seed: random.PRNGSeedMINSTD;
67+
readonly seed: random.PRNGSeedXORSHIFT;
6868

6969
/**
7070
* PRNG seed length.
@@ -74,7 +74,7 @@ interface PRNG {
7474
/**
7575
* PRNG state.
7676
*/
77-
state: random.PRNGStateMINSTD;
77+
state: random.PRNGStateXORSHIFT;
7878

7979
/**
8080
* PRNG state length.

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@
1616
* limitations under the License.
1717
*/
1818

19-
#ifndef STDLIB_RANDOM_BASE_MINSTD_H
20-
#define STDLIB_RANDOM_BASE_MINSTD_H
19+
#ifndef STDLIB_RANDOM_BASE_XORSHIFT_H
20+
#define STDLIB_RANDOM_BASE_XORSHIFT_H
2121

2222
#include "stdlib/random/base/shared.h"
2323
#include <stdint.h>
@@ -66,4 +66,4 @@ int8_t stdlib_base_random_xorshift_set( struct BasePRNGObject *obj, const void *
6666
}
6767
#endif
6868

69-
#endif // !STDLIB_RANDOM_BASE_MINSTD_H
69+
#endif // !STDLIB_RANDOM_BASE_XORSHIFT_H

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

Lines changed: 41 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -30,20 +30,19 @@ var isObject = require( '@stdlib/assert/is-plain-object' );
3030
var isBoolean = require( '@stdlib/assert/is-boolean' ).isPrimitive;
3131
var isCollection = require( '@stdlib/assert/is-collection' );
3232
var isPositiveInteger = require( '@stdlib/assert/is-positive-integer' ).isPrimitive;
33-
var isInt32Array = require( '@stdlib/assert/is-int32array' );
33+
var isUint32Array = require( '@stdlib/assert/is-uint32array' );
3434
var format = require( '@stdlib/string/format' );
35-
var INT32_MAX = require( '@stdlib/constants/int32/max' );
36-
var Int32Array = require( '@stdlib/array/int32' );
35+
var UINT32_MAX = require( '@stdlib/constants/uint32/max' );
36+
var Uint32Array = require( '@stdlib/array/uint32' );
3737
var gcopy = require( '@stdlib/blas/base/gcopy' );
3838
var typedarray2json = require( '@stdlib/array/to-json' );
3939
var randint32 = require( './rand_int32.js' );
4040

4141

4242
// VARIABLES //
4343

44-
var NORMALIZATION_CONSTANT = (INT32_MAX - 1)|0; // asm type annotation
45-
var MAX_SEED = (INT32_MAX - 1)|0; // asm type annotation
46-
var A = 16807|0; // asm type annotation
44+
var NORMALIZATION_CONSTANT = UINT32_MAX >>> 0; // asm type annotation
45+
var MAX_SEED = UINT32_MAX >>> 0; // asm type annotation
4746

4847
// Define the state array schema version:
4948
var STATE_ARRAY_VERSION = 1; // NOTE: anytime the state array schema changes, this value should be incremented!!!
@@ -67,7 +66,7 @@ var STATE_FIXED_LENGTH = 5; // 1 (version) + 1 (num_sections) + 1 (state_length)
6766
* Verifies state array integrity.
6867
*
6968
* @private
70-
* @param {Int32Array} state - state array
69+
* @param {Uint32Array} state - state array
7170
* @param {boolean} FLG - flag indicating whether the state array was provided as an option (true) or an argument (false)
7271
* @returns {(Error|null)} an error or `null`
7372
*/
@@ -108,13 +107,13 @@ function verifyState( state, FLG ) {
108107
* Returns a linear congruential pseudorandom number generator (LCG) based on Park and Miller.
109108
*
110109
* @param {Options} [options] - options
111-
* @param {PRNGSeedMINSTD} [options.seed] - pseudorandom number generator seed
112-
* @param {PRNGStateMINSTD} [options.state] - pseudorandom number generator state
110+
* @param {PRNGSeedXORSHIFT} [options.seed] - pseudorandom number generator seed
111+
* @param {PRNGStateXORSHIFT} [options.state] - pseudorandom number generator state
113112
* @param {boolean} [options.copy=true] - boolean indicating whether to copy a provided pseudorandom number generator state
114113
* @throws {TypeError} options argument must be an object
115114
* @throws {TypeError} a seed must be either a positive integer less than the maximum signed 32-bit integer or an array-like object containing integers less than the maximum signed 32-bit integer
116115
* @throws {RangeError} a numeric seed must be a positive integer less than the maximum signed 32-bit integer
117-
* @throws {TypeError} state must be an `Int32Array`
116+
* @throws {TypeError} state must be an `Uint32Array`
118117
* @throws {Error} must provide a valid state
119118
* @throws {TypeError} `copy` option must be a boolean
120119
* @returns {PRNG} LCG PRNG
@@ -132,7 +131,7 @@ function verifyState( state, FLG ) {
132131
* });
133132
*
134133
* var v = xorshift();
135-
* // returns 20739838
134+
* // returns 332584831
136135
*/
137136
function factory( options ) {
138137
var STATE;
@@ -156,8 +155,8 @@ function factory( options ) {
156155
if ( hasOwnProp( options, 'state' ) ) {
157156
state = options.state;
158157
opts.state = true;
159-
if ( !isInt32Array( state ) ) {
160-
throw new TypeError( format( 'invalid option. `%s` option must be an Int32Array. Option: `%s`.', 'state', state ) );
158+
if ( !isUint32Array( state ) ) {
159+
throw new TypeError( format( 'invalid option. `%s` option must be an Uint32Array. Option: `%s`.', 'state', state ) );
161160
}
162161
err = verifyState( state, true );
163162
if ( err ) {
@@ -166,14 +165,14 @@ function factory( options ) {
166165
if ( opts.copy === false ) {
167166
STATE = state;
168167
} else {
169-
STATE = new Int32Array( state.length );
168+
STATE = new Uint32Array( state.length );
170169
gcopy( state.length, state, 1, STATE, 1 );
171170
}
172171
// Create a state "view":
173-
state = new Int32Array( STATE.buffer, STATE.byteOffset+((STATE_SECTION_OFFSET+1)*STATE.BYTES_PER_ELEMENT), 1 );
172+
state = new Uint32Array( STATE.buffer, STATE.byteOffset+((STATE_SECTION_OFFSET+1)*STATE.BYTES_PER_ELEMENT), 1 );
174173

175174
// Create a seed "view":
176-
seed = new Int32Array( STATE.buffer, STATE.byteOffset+((SEED_SECTION_OFFSET+1)*STATE.BYTES_PER_ELEMENT), state[ SEED_SECTION_OFFSET ] );
175+
seed = new Uint32Array( STATE.buffer, STATE.byteOffset+((SEED_SECTION_OFFSET+1)*STATE.BYTES_PER_ELEMENT), state[ SEED_SECTION_OFFSET ] );
177176
}
178177
// If provided a PRNG state, we ignore the `seed` option...
179178
if ( seed === void 0 ) {
@@ -187,7 +186,7 @@ function factory( options ) {
187186
seed |= 0; // asm type annotation
188187
} else if ( isCollection( seed ) && seed.length > 0 ) {
189188
slen = seed.length;
190-
STATE = new Int32Array( STATE_FIXED_LENGTH+slen );
189+
STATE = new Uint32Array( STATE_FIXED_LENGTH+slen );
191190

192191
// Initialize sections:
193192
STATE[ 0 ] = STATE_ARRAY_VERSION;
@@ -199,25 +198,25 @@ function factory( options ) {
199198
gcopy.ndarray( slen, seed, 1, 0, STATE, 1, SEED_SECTION_OFFSET+1 );
200199

201200
// Create a state "view":
202-
state = new Int32Array( STATE.buffer, STATE.byteOffset+((STATE_SECTION_OFFSET+1)*STATE.BYTES_PER_ELEMENT), 1 );
201+
state = new Uint32Array( STATE.buffer, STATE.byteOffset+((STATE_SECTION_OFFSET+1)*STATE.BYTES_PER_ELEMENT), 1 );
203202

204203
// Create a seed "view":
205-
seed = new Int32Array( STATE.buffer, STATE.byteOffset+((SEED_SECTION_OFFSET+1)*STATE.BYTES_PER_ELEMENT), slen );
204+
seed = new Uint32Array( STATE.buffer, STATE.byteOffset+((SEED_SECTION_OFFSET+1)*STATE.BYTES_PER_ELEMENT), slen );
206205

207206
// Initialize the internal PRNG state:
208207
state[ 0 ] = seed[ 0 ];
209208
} else {
210209
throw new TypeError( format( 'invalid option. `%s` option must be either a positive integer less than the maximum signed 32-bit integer or an array-like object containing integer values less than the maximum signed 32-bit integer. Option: `%s`.', 'seed', seed ) );
211210
}
212211
} else {
213-
seed = randint32()|0; // asm type annotation
212+
seed = randint32() >>> 0; // asm type annotation
214213
}
215214
}
216215
} else {
217-
seed = randint32()|0; // asm type annotation
216+
seed = randint32() >>> 0; // asm type annotation
218217
}
219218
if ( state === void 0 ) {
220-
STATE = new Int32Array( STATE_FIXED_LENGTH+1 );
219+
STATE = new Uint32Array( STATE_FIXED_LENGTH+1 );
221220

222221
// Initialize sections:
223222
STATE[ 0 ] = STATE_ARRAY_VERSION;
@@ -227,10 +226,10 @@ function factory( options ) {
227226
STATE[ SEED_SECTION_OFFSET+1 ] = seed;
228227

229228
// Create a state "view":
230-
state = new Int32Array( STATE.buffer, STATE.byteOffset+((STATE_SECTION_OFFSET+1)*STATE.BYTES_PER_ELEMENT), 1 );
229+
state = new Uint32Array( STATE.buffer, STATE.byteOffset+((STATE_SECTION_OFFSET+1)*STATE.BYTES_PER_ELEMENT), 1 );
231230

232231
// Create a seed "view":
233-
seed = new Int32Array( STATE.buffer, STATE.byteOffset+((SEED_SECTION_OFFSET+1)*STATE.BYTES_PER_ELEMENT), 1 );
232+
seed = new Uint32Array( STATE.buffer, STATE.byteOffset+((SEED_SECTION_OFFSET+1)*STATE.BYTES_PER_ELEMENT), 1 );
234233

235234
// Initialize the internal PRNG state:
236235
state[ 0 ] = seed[ 0 ];
@@ -243,7 +242,7 @@ function factory( options ) {
243242
setReadOnlyAccessor( xorshift, 'byteLength', getStateSize );
244243
setReadOnly( xorshift, 'toJSON', toJSON );
245244
setReadOnly( xorshift, 'MIN', 1 );
246-
setReadOnly( xorshift, 'MAX', INT32_MAX-1 );
245+
setReadOnly( xorshift, 'MAX', UINT32_MAX );
247246
setReadOnly( xorshift, 'normalized', normalized );
248247

249248
setReadOnly( normalized, 'NAME', xorshift.NAME );
@@ -262,11 +261,11 @@ function factory( options ) {
262261
* Returns the PRNG seed.
263262
*
264263
* @private
265-
* @returns {PRNGSeedMINSTD} seed
264+
* @returns {PRNGSeedXORSHIFT} seed
266265
*/
267266
function getSeed() {
268267
var len = STATE[ SEED_SECTION_OFFSET ];
269-
return gcopy( len, seed, 1, new Int32Array( len ), 1 );
268+
return gcopy( len, seed, 1, new Uint32Array( len ), 1 );
270269
}
271270

272271
/**
@@ -317,11 +316,11 @@ function factory( options ) {
317316
* - The first element of each section following the preamble specifies the section length. The remaining section elements comprise the section contents.
318317
*
319318
* @private
320-
* @returns {PRNGStateMINSTD} current state
319+
* @returns {PRNGStateXORSHIFT} current state
321320
*/
322321
function getState() {
323322
var len = STATE.length;
324-
return gcopy( len, STATE, 1, new Int32Array( len ), 1 );
323+
return gcopy( len, STATE, 1, new Uint32Array( len ), 1 );
325324
}
326325

327326
/**
@@ -333,14 +332,14 @@ function factory( options ) {
333332
* - If PRNG state is "shared" and one sets the generator state to a state array of the same length, the PRNG state is updated (along with the state of all other PRNGs sharing the PRNG's state array).
334333
*
335334
* @private
336-
* @param {PRNGStateMINSTD} s - generator state
337-
* @throws {TypeError} must provide an `Int32Array`
335+
* @param {PRNGStateXORSHIFT} s - generator state
336+
* @throws {TypeError} must provide an `Uint32Array`
338337
* @throws {Error} must provide a valid state
339338
*/
340339
function setState( s ) {
341340
var err;
342-
if ( !isInt32Array( s ) ) {
343-
throw new TypeError( format( 'invalid argument. Must provide an Int32Array. Value: `%s`.', s ) );
341+
if ( !isUint32Array( s ) ) {
342+
throw new TypeError( format( 'invalid argument. Must provide an Uint32Array. Value: `%s`.', s ) );
344343
}
345344
err = verifyState( s, false );
346345
if ( err ) {
@@ -356,15 +355,15 @@ function factory( options ) {
356355
} else {
357356
// Check if we can reuse allocated memory...
358357
if ( s.length !== STATE.length ) {
359-
STATE = new Int32Array( s.length ); // reallocate
358+
STATE = new Uint32Array( s.length ); // reallocate
360359
}
361360
gcopy( s.length, s, 1, STATE, 1 );
362361
}
363362
// Create a new state "view":
364-
state = new Int32Array( STATE.buffer, STATE.byteOffset+((STATE_SECTION_OFFSET+1)*STATE.BYTES_PER_ELEMENT), 1 );
363+
state = new Uint32Array( STATE.buffer, STATE.byteOffset+((STATE_SECTION_OFFSET+1)*STATE.BYTES_PER_ELEMENT), 1 );
365364

366365
// Create a new seed "view":
367-
seed = new Int32Array( STATE.buffer, STATE.byteOffset+((SEED_SECTION_OFFSET+1)*STATE.BYTES_PER_ELEMENT), STATE[ SEED_SECTION_OFFSET ] );
366+
seed = new Uint32Array( STATE.buffer, STATE.byteOffset+((SEED_SECTION_OFFSET+1)*STATE.BYTES_PER_ELEMENT), STATE[ SEED_SECTION_OFFSET ] );
368367
}
369368

370369
/**
@@ -387,16 +386,18 @@ function factory( options ) {
387386
}
388387

389388
/**
390-
* Generates a pseudorandom integer on the interval \\( [1,2^{31}-1) \\).
389+
* Generates a pseudorandom integer on the interval \\( [1,2^{31}) \\).
391390
*
392391
* @private
393392
* @returns {integer32} pseudorandom integer
394393
*/
395394
function xorshift() {
396-
var s = state[ 0 ]|0; // asm type annotation
397-
s = ( (A*s)%INT32_MAX )|0; // asm type annotation
395+
var s = state[ 0 ] >>> 0; // asm type annotation
396+
s ^= s << 13;
397+
s ^= s >>> 17;
398+
s ^= s << 5;
398399
state[ 0 ] = s;
399-
return s|0; // asm type annotation
400+
return s >>> 0; // asm type annotation
400401
}
401402

402403
/**

0 commit comments

Comments
 (0)