/**
 * An updated version of the traditional MersenneTwister JavaScript class by
 * Sean McCullough (2010), based on code by Takuji Nishimura and Makoto
 * Matsumoto (1997 - 2002).
 *
 * For the 2010 code, see https://gist.github.com/banksean/300494.
 */ import { NumberMakrSettings } from "./types" ; /**
 * Configurable Mersenne Twister implementation.
 */ export class NumberMakr { /**
     * Length of the state vector.
     */ private readonly stateLength : number ; /**
     * Period of the state vector.
     */ private readonly statePeriod : number ; /**
     * Constant vector A.
     */ private readonly matrixA : number ; /**
     * Constant magic Array from matrixA.
     */ private readonly matrixAMagic : number [ ] ; /**
     * Most significant w-r bits.
     */ private readonly maskUpper : number ; /**
     * Least significant r bits.
     */ private readonly maskLower : number ; /**
     * Past states.
     */ private readonly stateVector : number [ ] ; /**
     * Place index in stateVector (if out of range, state must be reset).
     */ private stateIndex : number ; /**
     * The starting seed used to initialize.
     */ private seed : number | number [ ] ; param settings public constructor ( settings = { } ) { this . stateLength = settings . stateLength || 624 ; this . statePeriod = settings . statePeriod || 397 ; this . matrixA = settings . matrixA || 0x9908b0df ; this . maskUpper = settings . maskUpper || 0x80000000 ; this . maskLower = settings . maskLower || 0x7fffffff ; this . stateVector = new Array ( this . stateLength ) ; this . stateIndex = this . stateLength + 1 ; this . matrixAMagic = new Array ( 0x0 , this . matrixA ) ; this . resetFromSeed ( settings . seed || new Date ( ) . getTime ( ) ) ; } returns public getSeed ( ) { return this . seed ; } returns public getStateLength ( ) { return this . stateLength ; } returns public getStatePeriod ( ) { return this . statePeriod ; } returns public getMatrixA ( ) { return this . matrixA ; } returns public getMaskUpper ( ) { return this . maskUpper ; } returns public getMaskLower ( ) { return this . maskLower ; } param seedNew public resetFromSeed ( seedNew ) { this . stateVector [ 0 ] = ( seedNew as number ) >>> 0 ; let s ; for ( this . stateIndex = 1 ; this . stateIndex < this . stateLength ; this . stateIndex += 1 ) { s = this . stateVector [ this . stateIndex - 1 ] ^ ( this . stateVector [ this . stateIndex - 1 ] >>> 30 ) ; this . stateVector [ this . stateIndex ] = ( ( ( ( ( s & 0xffff0000 ) >>> 16 ) * 1812433253 ) << 16 ) + ( s & 0x0000ffff ) * 1812433253 + this . stateIndex ) >>> 0 ; } this . seed = seedNew ; } param keyInitial param keyLength remarks public resetFromArray ( keyInitial , keyLength = keyInitial . length ) { this . resetFromSeed ( 19650218 ) ; let i = 1 ; let j = 0 ; let k = this . stateLength > keyLength ? this . stateLength : keyLength ; while ( k > 0 ) { const s = this . stateVector [ i - 1 ] ^ ( this . stateVector [ i - 1 ] >>> 30 ) ; this . stateVector [ i ] = ( this . stateVector [ i ] ^ ( ( ( ( ( s & 0xffff0000 ) >>> 16 ) * 1664525 ) << 16 ) + ( s & 0x0000ffff ) * 1664525 + keyInitial [ j ] + j ) ) >>> 0 ; i += 1 ; j += 1 ; if ( i >= this . stateLength ) { this . stateVector [ 0 ] = this . stateVector [ this . stateLength - 1 ] ; i = 1 ; } if ( j >= keyLength ) { j = 0 ; } } for ( k = this . stateLength - 1 ; k ; k -= 1 ) { const s = this . stateVector [ i - 1 ] ^ ( this . stateVector [ i - 1 ] >>> 30 ) ; this . stateVector [ i ] = ( ( this . stateVector [ i ] ^ ( ( ( ( ( s & 0xffff0000 ) >>> 16 ) * 1566083941 ) << 16 ) + ( s & 0x0000ffff ) * 1566083941 ) ) - i ) >>> 0 ; i += 1 ; if ( i >= this . stateLength ) { this . stateVector [ 0 ] = this . stateVector [ this . stateLength - 1 ] ; i = 1 ; } } this . stateVector [ 0 ] = 0x80000000 ; this . seed = keyInitial ; } returns public randomInt32 ( ) { let y ; if ( this . stateIndex >= this . stateLength ) { let kk ; if ( this . stateIndex === this . stateLength + 1 ) { this . resetFromSeed ( 5489 ) ; } for ( kk = 0 ; kk < this . stateLength - this . statePeriod ; kk += 1 ) { y = ( this . stateVector [ kk ] & this . maskUpper ) | ( this . stateVector [ kk + 1 ] & this . maskLower ) ; this . stateVector [ kk ] = this . stateVector [ kk + this . statePeriod ] ^ ( y >>> 1 ) ^ this . matrixAMagic [ y & 0x1 ] ; } for ( ; kk < this . stateLength - 1 ; kk += 1 ) { y = ( this . stateVector [ kk ] & this . maskUpper ) | ( this . stateVector [ kk + 1 ] & this . maskLower ) ; this . stateVector [ kk ] = this . stateVector [ kk + ( this . statePeriod - this . stateLength ) ] ^ ( y >>> 1 ) ^ this . matrixAMagic [ y & 0x1 ] ; } y = ( this . stateVector [ this . stateLength - 1 ] & this . maskUpper ) | ( this . stateVector [ 0 ] & this . maskLower ) ; this . stateVector [ this . stateLength - 1 ] = this . stateVector [ this . statePeriod - 1 ] ^ ( y >>> 1 ) ^ this . matrixAMagic [ y & 0x1 ] ; this . stateIndex = 0 ; } y = this . stateVector [ this . stateIndex ] ; this . stateIndex += 1 ; y ^= y >>> 11 ; y ^= ( y << 7 ) & 0x9d2c5680 ; y ^= ( y << 15 ) & 0xefc60000 ; y ^= y >>> 18 ; return y >>> 0 ; } returns remarks public random ( ) { return this . randomInt32 ( ) * ( 1 / 4294967296 ) ; } returns public randomInt31 ( ) { return this . randomInt32 ( ) >>> 1 ; } returns remarks public randomReal1 ( ) { return this . randomInt32 ( ) * ( 1 / 4294967295 ) ; } returns remarks public randomReal3 ( ) { return ( this . randomInt32 ( ) + 0.5 ) * ( 1 / 4294967296 ) ; } returns public randomReal53Bit ( ) { const a = this . randomInt32 ( ) >>> 5 ; const b = this . randomInt32 ( ) >>> 6 ; return ( a * 67108864 + b ) * ( 1 / 9007199254740992 ) ; } param max returns public randomUnder ( max ) { return this . random ( ) * max ; } param min param max returns public randomWithin ( min , max ) { return this . randomUnder ( max - min ) + min ; } param max returns public randomInt ( max ) { return this . randomUnder ( max ) | 0 ; } param min param max returns public randomIntWithin ( min , max ) { return ( this . randomUnder ( max - min ) + min ) | 0 ; } returns public randomBoolean ( ) { return this . randomInt ( 2 ) === 1 ; } param probability returns public randomBooleanProbability ( probability ) { return this . random ( ) < probability ; } param numerator param denominator returns public randomBooleanFraction ( numerator , denominator ) { return this . random ( ) <= numerator / denominator ; } template T param array returns public randomArrayIndex < T > ( array ) { return this . randomIntWithin ( 0 , array . length ) ; } template T param array returns public randomArrayMember < T > ( array ) { return array [ this . randomArrayIndex ( array ) ] ; } }