factory.js (25841B)
1 /* eslint-disable max-lines, max-len */ 2 3 /** 4 * @license Apache-2.0 5 * 6 * Copyright (c) 2018 The Stdlib Authors. 7 * 8 * Licensed under the Apache License, Version 2.0 (the "License"); 9 * you may not use this file except in compliance with the License. 10 * You may obtain a copy of the License at 11 * 12 * http://www.apache.org/licenses/LICENSE-2.0 13 * 14 * Unless required by applicable law or agreed to in writing, software 15 * distributed under the License is distributed on an "AS IS" BASIS, 16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 * See the License for the specific language governing permissions and 18 * limitations under the License. 19 * 20 * 21 * ## Notice 22 * 23 * The original C code and copyright notice are from the [source implementation]{@link http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/MT2002/CODES/mt19937ar.c}. The implementation has been modified for JavaScript. 24 * 25 * ```text 26 * Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura, 27 * All rights reserved. 28 * 29 * Redistribution and use in source and binary forms, with or without 30 * modification, are permitted provided that the following conditions 31 * are met: 32 * 33 * 1. Redistributions of source code must retain the above copyright 34 * notice, this list of conditions and the following disclaimer. 35 * 36 * 2. Redistributions in binary form must reproduce the above copyright 37 * notice, this list of conditions and the following disclaimer in the 38 * documentation and/or other materials provided with the distribution. 39 * 40 * 3. The names of its contributors may not be used to endorse or promote 41 * products derived from this software without specific prior written 42 * permission. 43 * 44 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 45 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 46 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 47 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 48 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 49 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 50 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 51 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 52 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 53 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 54 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 55 * ``` 56 */ 57 58 'use strict'; 59 60 // MODULES // 61 62 var setReadOnly = require( '@stdlib/utils/define-nonenumerable-read-only-property' ); 63 var setReadOnlyAccessor = require( '@stdlib/utils/define-nonenumerable-read-only-accessor' ); 64 var setReadWriteAccessor = require( '@stdlib/utils/define-nonenumerable-read-write-accessor' ); 65 var hasOwnProp = require( '@stdlib/assert/has-own-property' ); 66 var isObject = require( '@stdlib/assert/is-plain-object' ); 67 var isCollection = require( '@stdlib/assert/is-collection' ); 68 var isUint32Array = require( '@stdlib/assert/is-uint32array' ); 69 var isBoolean = require( '@stdlib/assert/is-boolean' ).isPrimitive; 70 var isPositiveInteger = require( '@stdlib/assert/is-positive-integer' ).isPrimitive; 71 var FLOAT64_MAX_SAFE_INTEGER = require( '@stdlib/constants/float64/max-safe-integer' ); 72 var UINT32_MAX = require( '@stdlib/constants/uint32/max' ); 73 var Uint32Array = require( '@stdlib/array/uint32' ); 74 var max = require( '@stdlib/math/base/special/max' ); 75 var uimul = require( '@stdlib/math/base/special/uimul' ); 76 var gcopy = require( '@stdlib/blas/base/gcopy' ); 77 var typedarray2json = require( '@stdlib/array/to-json' ); 78 var randuint32 = require( './rand_uint32.js' ); 79 80 81 // VARIABLES // 82 83 // Define the size of the state array (see refs): 84 var N = 624; 85 86 // Define a (magic) constant used for indexing into the state array: 87 var M = 397; 88 89 // Define the maximum seed: 11111111111111111111111111111111 90 var MAX_SEED = UINT32_MAX >>> 0; // asm type annotation 91 92 // For seed arrays, define an initial state (magic) constant: 19650218 => 00000001001010111101011010101010 93 var SEED_ARRAY_INIT_STATE = 19650218 >>> 0; // asm type annotation 94 95 // Define a mask for the most significant `w-r` bits, where `w` is the word size (32 bits) and `r` is the separation point of one word (see refs): 2147483648 => 0x80000000 => 10000000000000000000000000000000 96 var UPPER_MASK = 0x80000000 >>> 0; // asm type annotation 97 98 // Define a mask for the least significant `r` bits (see refs): 2147483647 => 0x7fffffff => 01111111111111111111111111111111 99 var LOWER_MASK = 0x7fffffff >>> 0; // asm type annotation 100 101 // Define a multiplier (see Knuth TAOCP Vol2. 3rd Ed. P.106): 1812433253 => 01101100000001111000100101100101 102 var KNUTH_MULTIPLIER = 1812433253 >>> 0; // asm type annotation 103 104 // Define a (magic) multiplier: 1664525 => 00000000000110010110011000001101 105 var MAGIC_MULTIPLIER_1 = 1664525 >>> 0; // asm type annotation 106 107 // Define a (magic) multiplier: 1566083941 => 01011101010110001000101101100101 108 var MAGIC_MULTIPLIER_2 = 1566083941 >>> 0; // asm type annotation 109 110 // Define a tempering coefficient: 2636928640 => 0x9d2c5680 => 10011101001011000101011010000000 111 var TEMPERING_COEFFICIENT_1 = 0x9d2c5680 >>> 0; // asm type annotation 112 113 // Define a tempering coefficient: 4022730752 => 0xefc60000 => 11101111110001100000000000000000 114 var TEMPERING_COEFFICIENT_2 = 0xefc60000 >>> 0; // asm type annotation 115 116 // Define a constant vector `a` (see refs): 2567483615 => 0x9908b0df => 10011001000010001011000011011111 117 var MATRIX_A = 0x9908b0df >>> 0; // asm type annotation 118 119 // MAG01[x] = x * MATRIX_A; for x = {0,1} 120 var MAG01 = [ 0x0 >>> 0, MATRIX_A >>> 0 ]; // asm type annotation 121 122 // Define a normalization constant when generating double-precision floating-point numbers: 2^53 => 9007199254740992 123 var FLOAT64_NORMALIZATION_CONSTANT = 1.0 / ( FLOAT64_MAX_SAFE_INTEGER+1.0 ); // eslint-disable-line id-length 124 125 // 2^26: 67108864 126 var TWO_26 = 67108864 >>> 0; // asm type annotation 127 128 // 2^32: 2147483648 => 0x80000000 => 10000000000000000000000000000000 129 var TWO_32 = 0x80000000 >>> 0; // asm type annotation 130 131 // 1 (as a 32-bit unsigned integer): 1 => 0x1 => 00000000000000000000000000000001 132 var ONE = 0x1 >>> 0; // asm type annotation 133 134 // Define the maximum normalized pseudorandom double-precision floating-point number: ( (((2^32-1)>>>5)*2^26)+( (2^32-1)>>>6) ) / 2^53 135 var MAX_NORMALIZED = FLOAT64_MAX_SAFE_INTEGER * FLOAT64_NORMALIZATION_CONSTANT; 136 137 // Define the state array schema version: 138 var STATE_ARRAY_VERSION = 1; // NOTE: anytime the state array schema changes, this value should be incremented!!! 139 140 // Define the number of sections in the state array: 141 var NUM_STATE_SECTIONS = 3; // state, other, seed 142 143 // Define the index offset of the "state" section in the state array: 144 var STATE_SECTION_OFFSET = 2; // | version | num_sections | state_length | ...state | other_length | state_index | seed_length | ...seed | 145 146 // Define the index offset of the "other" section in the state array: 147 var OTHER_SECTION_OFFSET = N + 3; // | version | num_sections | state_length | ...state | other_length | state_index | seed_length | ...seed | 148 149 // Define the index offset of the seed section in the state array: 150 var SEED_SECTION_OFFSET = N + 5; // | version | num_sections | state_length | ...state | other_length | state_index | seed_length | ...seed | 151 152 // Define the length of the "fixed" length portion of the state array: 153 var STATE_FIXED_LENGTH = N + 6; // 1 (version) + 1 (num_sections) + 1 (state_length) + N (state) + 1 (other_length) + 1 (state_index) + 1 (seed_length) 154 155 156 // FUNCTIONS // 157 158 /** 159 * Verifies state array integrity. 160 * 161 * @private 162 * @param {Uint32Array} state - state array 163 * @param {boolean} FLG - flag indicating whether the state array was provided as an option (true) or an argument (false) 164 * @returns {(Error|null)} an error or `null` 165 */ 166 function verifyState( state, FLG ) { 167 var s1; 168 if ( FLG ) { 169 s1 = 'option'; 170 } else { 171 s1 = 'argument'; 172 } 173 // The state array must have a minimum length... 174 if ( state.length < STATE_FIXED_LENGTH+1 ) { 175 return new RangeError( 'invalid '+s1+'. `state` array has insufficient length.' ); 176 } 177 // The first element of the state array must equal the supported state array schema version... 178 if ( state[ 0 ] !== STATE_ARRAY_VERSION ) { 179 return new RangeError( 'invalid '+s1+'. `state` array has an incompatible schema version. Expected: '+STATE_ARRAY_VERSION+'. Actual: '+state[ 0 ]+'.' ); 180 } 181 // The second element of the state array must contain the number of sections... 182 if ( state[ 1 ] !== NUM_STATE_SECTIONS ) { 183 return new RangeError( 'invalid '+s1+'. `state` array has an incompatible number of sections. Expected: '+NUM_STATE_SECTIONS+'. Actual: '+state[ 1 ]+'.' ); 184 } 185 // The length of the "state" section must equal `N`... 186 if ( state[ STATE_SECTION_OFFSET ] !== N ) { 187 return new RangeError( 'invalid '+s1+'. `state` array has an incompatible state length. Expected: '+N+'. Actual: '+state[ STATE_SECTION_OFFSET ]+'.' ); 188 } 189 // The length of the "other" section must equal `1`... 190 if ( state[ OTHER_SECTION_OFFSET ] !== 1 ) { 191 return new RangeError( 'invalid '+s1+'. `state` array has an incompatible section length. Expected: '+(1).toString()+'. Actual: '+state[ OTHER_SECTION_OFFSET ]+'.' ); 192 } 193 // The length of the "seed" section much match the empirical length... 194 if ( state[ SEED_SECTION_OFFSET ] !== state.length-STATE_FIXED_LENGTH ) { 195 return new RangeError( 'invalid '+s1+'. `state` array length is incompatible with seed section length. Expected: '+(state.length-STATE_FIXED_LENGTH)+'. Actual: '+state[ SEED_SECTION_OFFSET ]+'.' ); 196 } 197 return null; 198 } 199 200 /** 201 * Returns an initial PRNG state. 202 * 203 * @private 204 * @param {Uint32Array} state - state array 205 * @param {PositiveInteger} N - state size 206 * @param {uinteger32} s - seed 207 * @returns {Uint32Array} state array 208 */ 209 function createState( state, N, s ) { 210 var i; 211 212 // Set the first element of the state array to the provided seed: 213 state[ 0 ] = s >>> 0; // equivalent to `s & 0xffffffffUL` in original C implementation 214 215 // Initialize the remaining state array elements: 216 for ( i = 1; i < N; i++ ) { 217 /* 218 * In the original C implementation (see `init_genrand()`), 219 * 220 * ```c 221 * mt[i] = (KNUTH_MULTIPLIER * (mt[i-1] ^ (mt[i-1] >> 30)) + i) 222 * ``` 223 * 224 * In order to replicate this in JavaScript, we must emulate C-like multiplication of unsigned 32-bit integers. 225 */ 226 s = state[ i-1 ]>>>0; // asm type annotation 227 s = ( s^(s>>>30) )>>>0; // asm type annotation 228 state[ i ] = ( uimul( s, KNUTH_MULTIPLIER ) + i )>>>0; // asm type annotation 229 } 230 return state; 231 } 232 233 /** 234 * Initializes a PRNG state array according to a seed array. 235 * 236 * @private 237 * @param {Uint32Array} state - state array 238 * @param {NonNegativeInteger} N - state array length 239 * @param {Collection} seed - seed array 240 * @param {NonNegativeInteger} M - seed array length 241 * @returns {Uint32Array} state array 242 */ 243 function initState( state, N, seed, M ) { 244 var s; 245 var i; 246 var j; 247 var k; 248 249 i = 1; 250 j = 0; 251 for ( k = max( N, M ); k > 0; k-- ) { 252 /* 253 * In the original C implementation (see `init_by_array()`), 254 * 255 * ```c 256 * mt[i] = (mt[i]^((mt[i-1]^(mt[i-1]>>30))*1664525UL)) + seed[j] + j; 257 * ``` 258 * 259 * In order to replicate this in JavaScript, we must emulate C-like multiplication of unsigned 32-bit integers. 260 */ 261 s = state[ i-1 ]>>>0; // asm type annotation 262 s = ( s^(s>>>30) )>>>0; // asm type annotation 263 s = ( uimul( s, MAGIC_MULTIPLIER_1 ) )>>>0; // asm type annotation 264 state[ i ] = ( ((state[i]>>>0)^s) + seed[j] + j )>>>0; /* non-linear */ // asm type annotation 265 266 i += 1; 267 j += 1; 268 if ( i >= N ) { 269 state[ 0 ] = state[ N-1 ]; 270 i = 1; 271 } 272 if ( j >= M ) { 273 j = 0; 274 } 275 } 276 for ( k = N-1; k > 0; k-- ) { 277 /* 278 * In the original C implementation (see `init_by_array()`), 279 * 280 * ```c 281 * mt[i] = (mt[i]^((mt[i-1]^(mt[i-1]>>30))*1566083941UL)) - i; 282 * ``` 283 * 284 * In order to replicate this in JavaScript, we must emulate C-like multiplication of unsigned 32-bit integers. 285 */ 286 s = state[ i-1 ]>>>0; // asm type annotation 287 s = ( s^(s>>>30) )>>>0; // asm type annotation 288 s = ( uimul( s, MAGIC_MULTIPLIER_2 ) )>>>0; // asm type annotation 289 state[ i ] = ( ((state[i]>>>0)^s) - i )>>>0; /* non-linear */ // asm type annotation 290 291 i += 1; 292 if ( i >= N ) { 293 state[ 0 ] = state[ N-1 ]; 294 i = 1; 295 } 296 } 297 // Ensure a non-zero initial state array: 298 state[ 0 ] = TWO_32; // MSB (most significant bit) is 1 299 300 return state; 301 } 302 303 /** 304 * Updates a PRNG's internal state by generating the next `N` words. 305 * 306 * @private 307 * @param {Uint32Array} state - state array 308 * @returns {Uint32Array} state array 309 */ 310 function twist( state ) { 311 var w; 312 var i; 313 var j; 314 var k; 315 316 k = N - M; 317 for ( i = 0; i < k; i++ ) { 318 w = ( state[i]&UPPER_MASK ) | ( state[i+1]&LOWER_MASK ); 319 state[ i ] = state[ i+M ] ^ ( w>>>1 ) ^ MAG01[ w&ONE ]; 320 } 321 j = N - 1; 322 for ( ; i < j; i++ ) { 323 w = ( state[i]&UPPER_MASK ) | ( state[i+1]&LOWER_MASK ); 324 state[ i ] = state[ i-k ] ^ ( w>>>1 ) ^ MAG01[ w&ONE ]; 325 } 326 w = ( state[j]&UPPER_MASK ) | ( state[0]&LOWER_MASK ); 327 state[ j ] = state[ M-1 ] ^ ( w>>>1 ) ^ MAG01[ w&ONE ]; 328 return state; 329 } 330 331 332 // MAIN // 333 334 /** 335 * Returns a 32-bit Mersenne Twister pseudorandom number generator. 336 * 337 * ## Notes 338 * 339 * - In contrast to the original C implementation, array seeds of length `1` are considered integer seeds. This ensures that the seed `[ 1234 ]` generates the same output as the seed `1234`. In the original C implementation, the two seeds would yield different output, which is **not** obvious from a user perspective. 340 * 341 * @param {Options} [options] - options 342 * @param {PRNGSeedMT19937} [options.seed] - pseudorandom number generator seed 343 * @param {PRNGStateMT19937} [options.state] - pseudorandom number generator state 344 * @param {boolean} [options.copy=true] - boolean indicating whether to copy a provided pseudorandom number generator state 345 * @throws {TypeError} options argument must be an object 346 * @throws {TypeError} a seed must be either a positive integer less than or equal to the maximum unsigned 32-bit integer or an array-like object containing integers less than or equal to the maximum unsigned 32-bit integer 347 * @throws {RangeError} a numeric seed must be a positive integer less than or equal to the maximum unsigned 32-bit integer 348 * @throws {TypeError} state must be a `Uint32Array` 349 * @throws {Error} must provide a valid state 350 * @throws {TypeError} `copy` option must be a boolean 351 * @returns {PRNG} Mersenne Twister PRNG 352 * 353 * @example 354 * var mt19937 = factory(); 355 * 356 * var v = mt19937(); 357 * // returns <number> 358 * 359 * @example 360 * // Return a seeded Mersenne Twister PRNG: 361 * var mt19937 = factory({ 362 * 'seed': 1234 363 * }); 364 * 365 * var v = mt19937(); 366 * // returns 822569775 367 */ 368 function factory( options ) { 369 var STATE; 370 var state; 371 var opts; 372 var seed; 373 var slen; 374 var err; 375 376 opts = {}; 377 if ( arguments.length ) { 378 if ( !isObject( options ) ) { 379 throw new TypeError( 'invalid argument. Options argument must be an object. Value: `' + options + '`.' ); 380 } 381 if ( hasOwnProp( options, 'copy' ) ) { 382 opts.copy = options.copy; 383 if ( !isBoolean( options.copy ) ) { 384 throw new TypeError( 'invalid option. `copy` option must be a boolean. Option: `' + options.copy + '`.' ); 385 } 386 } 387 if ( hasOwnProp( options, 'state' ) ) { 388 state = options.state; 389 opts.state = true; 390 if ( !isUint32Array( state ) ) { 391 throw new TypeError( 'invalid option. `state` option must be a Uint32Array. Option: `' + state + '`.' ); 392 } 393 err = verifyState( state, true ); 394 if ( err ) { 395 throw err; 396 } 397 if ( opts.copy === false ) { 398 STATE = state; 399 } else { 400 STATE = new Uint32Array( state.length ); 401 gcopy( state.length, state, 1, STATE, 1 ); 402 } 403 // Create a state "view": 404 state = new Uint32Array( STATE.buffer, STATE.byteOffset+((STATE_SECTION_OFFSET+1)*STATE.BYTES_PER_ELEMENT), N ); 405 406 // Create a seed "view": 407 seed = new Uint32Array( STATE.buffer, STATE.byteOffset+((SEED_SECTION_OFFSET+1)*STATE.BYTES_PER_ELEMENT), state[ SEED_SECTION_OFFSET ] ); 408 } 409 // If provided a PRNG state, we ignore the `seed` option... 410 if ( seed === void 0 ) { 411 if ( hasOwnProp( options, 'seed' ) ) { 412 seed = options.seed; 413 opts.seed = true; 414 if ( isPositiveInteger( seed ) ) { 415 if ( seed > MAX_SEED ) { 416 throw new RangeError( 'invalid option. `seed` option must be a positive integer less than or equal to the maximum unsigned 32-bit integer. Option: `' + seed + '`.' ); 417 } 418 seed >>>= 0; // asm type annotation 419 } else if ( isCollection( seed ) === false || seed.length < 1 ) { 420 throw new TypeError( 'invalid option. `seed` option must be either a positive integer less than or equal to the maximum unsigned 32-bit integer or an array-like object containing integer values less than or equal to the maximum unsigned 32-bit integer. Option: `' + seed + '`.' ); 421 } else if ( seed.length === 1 ) { 422 seed = seed[ 0 ]; 423 if ( !isPositiveInteger( seed ) ) { 424 throw new TypeError( 'invalid option. `seed` option must be either a positive integer less than or equal to the maximum unsigned 32-bit integer or an array-like object containing integer values less than or equal to the maximum unsigned 32-bit integer. Option: `' + seed + '`.' ); 425 } 426 if ( seed > MAX_SEED ) { 427 throw new RangeError( 'invalid option. `seed` option must be either a positive integer less than or equal to the maximum unsigned 32-bit integer or an array-like object containing integer values less than or equal to the maximum unsigned 32-bit integer. Option: `' + seed + '`.' ); 428 } 429 seed >>>= 0; // asm type annotation 430 } else { 431 slen = seed.length; 432 STATE = new Uint32Array( STATE_FIXED_LENGTH+slen ); 433 434 // Initialize sections: 435 STATE[ 0 ] = STATE_ARRAY_VERSION; 436 STATE[ 1 ] = NUM_STATE_SECTIONS; 437 STATE[ STATE_SECTION_OFFSET ] = N; 438 STATE[ OTHER_SECTION_OFFSET ] = 1; 439 STATE[ OTHER_SECTION_OFFSET+1 ] = N; // state index 440 STATE[ SEED_SECTION_OFFSET ] = slen; 441 442 // Copy the provided seed array to prevent external mutation, as mutation would lead to an inability to reproduce PRNG values according to the PRNG's stated seed: 443 gcopy.ndarray( slen, seed, 1, 0, STATE, 1, SEED_SECTION_OFFSET+1 ); 444 445 // Create a state "view": 446 state = new Uint32Array( STATE.buffer, STATE.byteOffset+((STATE_SECTION_OFFSET+1)*STATE.BYTES_PER_ELEMENT), N ); 447 448 // Create a seed "view": 449 seed = new Uint32Array( STATE.buffer, STATE.byteOffset+((SEED_SECTION_OFFSET+1)*STATE.BYTES_PER_ELEMENT), slen ); 450 451 // Initialize the internal PRNG state: 452 state = createState( state, N, SEED_ARRAY_INIT_STATE ); 453 state = initState( state, N, seed, slen ); 454 } 455 } else { 456 seed = randuint32() >>> 0; // asm type annotation 457 } 458 } 459 } else { 460 seed = randuint32() >>> 0; // asm type annotation 461 } 462 if ( state === void 0 ) { 463 STATE = new Uint32Array( STATE_FIXED_LENGTH+1 ); 464 465 // Initialize sections: 466 STATE[ 0 ] = STATE_ARRAY_VERSION; 467 STATE[ 1 ] = NUM_STATE_SECTIONS; 468 STATE[ STATE_SECTION_OFFSET ] = N; 469 STATE[ OTHER_SECTION_OFFSET ] = 1; 470 STATE[ OTHER_SECTION_OFFSET+1 ] = N; // state index 471 STATE[ SEED_SECTION_OFFSET ] = 1; 472 STATE[ SEED_SECTION_OFFSET+1 ] = seed; 473 474 // Create a state "view": 475 state = new Uint32Array( STATE.buffer, STATE.byteOffset+((STATE_SECTION_OFFSET+1)*STATE.BYTES_PER_ELEMENT), N ); 476 477 // Create a seed "view": 478 seed = new Uint32Array( STATE.buffer, STATE.byteOffset+((SEED_SECTION_OFFSET+1)*STATE.BYTES_PER_ELEMENT), 1 ); 479 480 // Initialize the internal PRNG state: 481 state = createState( state, N, seed ); 482 } 483 // Note: property order matters in order to maintain consistency of PRNG "shape" (hidden classes). 484 setReadOnly( mt19937, 'NAME', 'mt19937' ); 485 setReadOnlyAccessor( mt19937, 'seed', getSeed ); 486 setReadOnlyAccessor( mt19937, 'seedLength', getSeedLength ); 487 setReadWriteAccessor( mt19937, 'state', getState, setState ); 488 setReadOnlyAccessor( mt19937, 'stateLength', getStateLength ); 489 setReadOnlyAccessor( mt19937, 'byteLength', getStateSize ); 490 setReadOnly( mt19937, 'toJSON', toJSON ); 491 setReadOnly( mt19937, 'MIN', 1 ); 492 setReadOnly( mt19937, 'MAX', UINT32_MAX ); 493 setReadOnly( mt19937, 'normalized', normalized ); 494 495 setReadOnly( normalized, 'NAME', mt19937.NAME ); 496 setReadOnlyAccessor( normalized, 'seed', getSeed ); 497 setReadOnlyAccessor( normalized, 'seedLength', getSeedLength ); 498 setReadWriteAccessor( normalized, 'state', getState, setState ); 499 setReadOnlyAccessor( normalized, 'stateLength', getStateLength ); 500 setReadOnlyAccessor( normalized, 'byteLength', getStateSize ); 501 setReadOnly( normalized, 'toJSON', toJSON ); 502 setReadOnly( normalized, 'MIN', 0.0 ); 503 setReadOnly( normalized, 'MAX', MAX_NORMALIZED ); 504 505 return mt19937; 506 507 /** 508 * Returns the PRNG seed. 509 * 510 * @private 511 * @returns {PRNGSeedMT19937} seed 512 */ 513 function getSeed() { 514 var len = STATE[ SEED_SECTION_OFFSET ]; 515 return gcopy( len, seed, 1, new Uint32Array( len ), 1 ); 516 } 517 518 /** 519 * Returns the PRNG seed length. 520 * 521 * @private 522 * @returns {PositiveInteger} seed length 523 */ 524 function getSeedLength() { 525 return STATE[ SEED_SECTION_OFFSET ]; 526 } 527 528 /** 529 * Returns the PRNG state length. 530 * 531 * @private 532 * @returns {PositiveInteger} state length 533 */ 534 function getStateLength() { 535 return STATE.length; 536 } 537 538 /** 539 * Returns the PRNG state size (in bytes). 540 * 541 * @private 542 * @returns {PositiveInteger} state size (in bytes) 543 */ 544 function getStateSize() { 545 return STATE.byteLength; 546 } 547 548 /** 549 * Returns the current PRNG state. 550 * 551 * ## Notes 552 * 553 * - The PRNG state array is comprised of a preamble followed by `3` sections: 554 * 555 * 0. preamble (version + number of sections) 556 * 1. internal PRNG state 557 * 2. auxiliary state information 558 * 3. PRNG seed 559 * 560 * - The first element of the PRNG state array preamble is the state array schema version. 561 * 562 * - The second element of the PRNG state array preamble is the number of state array sections (i.e., `3`). 563 * 564 * - The first element of each section following the preamble specifies the section length. The remaining section elements comprise the section contents. 565 * 566 * @private 567 * @returns {PRNGStateMT19937} current state 568 */ 569 function getState() { 570 var len = STATE.length; 571 return gcopy( len, STATE, 1, new Uint32Array( len ), 1 ); 572 } 573 574 /** 575 * Sets the PRNG state. 576 * 577 * ## Notes 578 * 579 * - If PRNG state is "shared" (meaning a state array was provided during PRNG creation and **not** copied) and one sets the generator state to a state array having a different length, the PRNG does **not** update the existing shared state and, instead, points to the newly provided state array. In order to synchronize PRNG output according to the new shared state array, the state array for **each** relevant PRNG must be **explicitly** set. 580 * - 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). 581 * 582 * @private 583 * @param {PRNGStateMT19937} s - generator state 584 * @throws {TypeError} must provide a `Uint32Array` 585 * @throws {Error} must provide a valid state 586 */ 587 function setState( s ) { 588 var err; 589 if ( !isUint32Array( s ) ) { 590 throw new TypeError( 'invalid argument. Must provide a Uint32Array. Value: `' + s + '`.' ); 591 } 592 err = verifyState( s, false ); 593 if ( err ) { 594 throw err; 595 } 596 if ( opts.copy === false ) { 597 if ( opts.state && s.length === STATE.length ) { 598 gcopy( s.length, s, 1, STATE, 1 ); // update current shared state 599 } else { 600 STATE = s; // point to new shared state 601 opts.state = true; // setting this flag allows updating a shared state even if a state array was not provided at PRNG creation 602 } 603 } else { 604 // Check if we can reuse allocated memory... 605 if ( s.length !== STATE.length ) { 606 STATE = new Uint32Array( s.length ); // reallocate 607 } 608 gcopy( s.length, s, 1, STATE, 1 ); 609 } 610 // Create a new state "view": 611 state = new Uint32Array( STATE.buffer, STATE.byteOffset+((STATE_SECTION_OFFSET+1)*STATE.BYTES_PER_ELEMENT), N ); 612 613 // Create a new seed "view": 614 seed = new Uint32Array( STATE.buffer, STATE.byteOffset+((SEED_SECTION_OFFSET+1)*STATE.BYTES_PER_ELEMENT), STATE[ SEED_SECTION_OFFSET ] ); 615 } 616 617 /** 618 * Serializes the pseudorandom number generator as a JSON object. 619 * 620 * ## Notes 621 * 622 * - `JSON.stringify()` implicitly calls this method when stringifying a PRNG. 623 * 624 * @private 625 * @returns {Object} JSON representation 626 */ 627 function toJSON() { 628 var out = {}; 629 out.type = 'PRNG'; 630 out.name = mt19937.NAME; 631 out.state = typedarray2json( STATE ); 632 out.params = []; 633 return out; 634 } 635 636 /** 637 * Generates a pseudorandom integer on the interval \\( [1,2^{32}-1) \\). 638 * 639 * @private 640 * @returns {uinteger32} pseudorandom integer 641 * 642 * @example 643 * var r = mt19937(); 644 * // returns <number> 645 */ 646 function mt19937() { 647 var r; 648 var i; 649 650 // Retrieve the current state index: 651 i = STATE[ OTHER_SECTION_OFFSET+1 ]; 652 653 // Determine whether we need to update the PRNG state: 654 if ( i >= N ) { 655 state = twist( state ); 656 i = 0; 657 } 658 // Get the next word of "raw"/untempered state: 659 r = state[ i ]; 660 661 // Update the state index: 662 STATE[ OTHER_SECTION_OFFSET+1 ] = i + 1; 663 664 // Tempering transform to compensate for the reduced dimensionality of equidistribution: 665 r ^= r >>> 11; 666 r ^= ( r << 7 ) & TEMPERING_COEFFICIENT_1; 667 r ^= ( r << 15 ) & TEMPERING_COEFFICIENT_2; 668 r ^= r >>> 18; 669 670 return r >>> 0; 671 } 672 673 /** 674 * Generates a pseudorandom number on the interval \\( [0,1) \\). 675 * 676 * ## Notes 677 * 678 * - The original C implementation credits Isaku Wada for this algorithm (2002/01/09). 679 * 680 * @private 681 * @returns {number} pseudorandom number 682 * 683 * @example 684 * var r = normalized(); 685 * // returns <number> 686 */ 687 function normalized() { 688 var x = mt19937() >>> 5; 689 var y = mt19937() >>> 6; 690 return ( (x*TWO_26)+y ) * FLOAT64_NORMALIZATION_CONSTANT; 691 } 692 } 693 694 695 // EXPORTS // 696 697 module.exports = factory;