Skip to content

Commit

Permalink
Merge branch 'hotfix/v1.0.2'
Browse files Browse the repository at this point in the history
* hotfix/v1.0.2:
  Release hotfix v1.0.2
  Add ES2015+ guidance
  Refactor for readability
  Reduce repetitive logic
  • Loading branch information
dsibilly committed Jun 18, 2019
2 parents 3a1cadb + 8a03855 commit ea5dffa
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 91 deletions.
35 changes: 21 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,58 +17,65 @@ $ npm install @dsibilly/mersenne-twister
Get an instance of RNG:

```javascript
var MersenneTwister = require('@dsibilly/mersenne-twister'),
const MersenneTwister = require('@dsibilly/mersenne-twister').default,
rng = = new MersenneTwister();
```

...or with ES2015+ `import`:
```javascript
import MersenneTwister from '@dsibilly/mersenne-twister';

const rng = new MersenneTwister();
```

#### Seeding the RNG

```javascript
var rng2 = new MersenneTwister(4567);
var rng3 = new MersenneTwister([
// You can also seed with an array of values
123,
456,
789
]);
const rng2 = new MersenneTwister(4567),
rng3 = new MersenneTwister([
// You can also seed with an array of values
123,
456,
789
]);
```

#### Generating Numbers

Generate a random 32-bit integer:

```javascript
var result = rng.randomInt();
const result = rng.randomInt();
```

Generate a random 31-bit integer::

```javascript
var result = rng.randomInt31();
const result = rng.randomInt31();
```

Generate a random number between 0 and 1, exclusive (e.g. 0 < n < 1):

```javascript
var result = rng.randomExclusive();
const result = rng.randomExclusive();
```

Generate a random number where 0 <= n < 1:

```javascript
var result = rng.random();
const result = rng.random();
```

Generate a random number between 0 and 1, inclusive (e.g. 0 <= n <= 1):

```javascript
var result = rng.randomInclusive();
const result = rng.randomInclusive();
```

Generate a random 53-bit number, 0 <= n <= 1:

```javascript
var result = rng.randomLong();
const result = rng.randomLong();
```

## License
Expand Down
100 changes: 46 additions & 54 deletions js/mersenne-twister.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,43 +15,32 @@ const _MersenneTwister = _make({
},

randomInt () {
const mag01 = [0x0, _MersenneTwister.MATRIX_A];
const mag01 = [0x0, _MersenneTwister.RATIONAL_NORMAL_FORM_TWIST_MATRIX],
setY = index => (this.state[index] & _MersenneTwister.UPPER_MASK) | (this.state[index + 1] & _MersenneTwister.LOWER_MASK);

let y;

if (this.mtIndex >= _MersenneTwister.N) {
let kk;

/*
This code is unreachable in this revision, as there is no
condition under which a _MersenneTwister object can be
created wherein _initWithSeed() is not called...
*/
/*
if (this.mtIndex === _MersenneTwister.N + 1) {
// If _initWithSeed has not been called, a default initial seed is used.
this._initWithSeed(5489);
}
*/
if (this.stateIndex >= _MersenneTwister.DEGREE_OF_RECURRENCE) {
let index;

for (kk = 0; kk < _MersenneTwister.N - _MersenneTwister.M; kk += 1) {
y = (this.mt[kk] & _MersenneTwister.UPPER_MASK) | (this.mt[kk + 1] & _MersenneTwister.LOWER_MASK);
this.mt[kk] = this.mt[kk + _MersenneTwister.M] ^ (y >>> 1) ^ mag01[y & 0x1];
for (index = 0; index < _MersenneTwister.DEGREE_OF_RECURRENCE - _MersenneTwister.MIDDLE_WORD; index += 1) {
y = setY(index);
this.state[index] = this.state[index + _MersenneTwister.MIDDLE_WORD] ^ (y >>> 1) ^ mag01[y & 0x1];
}

for (; kk < _MersenneTwister.N - 1; kk += 1) {
y = (this.mt[kk] & _MersenneTwister.UPPER_MASK) | (this.mt[kk + 1] & _MersenneTwister.LOWER_MASK);
this.mt[kk] = this.mt[kk + (_MersenneTwister.M - _MersenneTwister.N)] ^ (y >>> 1) ^ mag01[y & 0x1];
for (; index < _MersenneTwister.DEGREE_OF_RECURRENCE - 1; index += 1) {
y = setY(index);
this.state[index] = this.state[index + (_MersenneTwister.MIDDLE_WORD - _MersenneTwister.DEGREE_OF_RECURRENCE)] ^ (y >>> 1) ^ mag01[y & 0x1];
}

y = (this.mt[_MersenneTwister.N - 1] & _MersenneTwister.UPPER_MASK) | (this.mt[0] & _MersenneTwister.LOWER_MASK);
this.mt[_MersenneTwister.N - 1] = this.mt[_MersenneTwister.M - 1] ^ (y >>> 1) ^ mag01[y & 0x1];
y = (this.state[_MersenneTwister.DEGREE_OF_RECURRENCE - 1] & _MersenneTwister.UPPER_MASK) | (this.state[0] & _MersenneTwister.LOWER_MASK);
this.state[_MersenneTwister.DEGREE_OF_RECURRENCE - 1] = this.state[_MersenneTwister.MIDDLE_WORD - 1] ^ (y >>> 1) ^ mag01[y & 0x1];

this.mtIndex = 0;
this.stateIndex = 0;
}

y = this.mt[this.mtIndex];
this.mtIndex += 1;
y = this.state[this.stateIndex];
this.stateIndex += 1;

y ^= y >>> 11;
y ^= (y << 7) & 0x9d2c5680;
Expand All @@ -77,8 +66,8 @@ const _MersenneTwister = _make({
seed = new Date().getTime();
}

this.mt = new Array(_MersenneTwister.N); // State vector Array
this.mtIndex = _MersenneTwister.N + 1; // mt[N] is not initialized
this.state = new Array(_MersenneTwister.DEGREE_OF_RECURRENCE); // State vector Array
this.stateIndex = _MersenneTwister.DEGREE_OF_RECURRENCE + 1; // mt[N] is not initialized

if (seed.constructor === Array) {
this._initWithArray(seed);
Expand All @@ -90,65 +79,68 @@ const _MersenneTwister = _make({
},

_initWithArray (array) {
const setAndResetBigI = i => {
if (i >= _MersenneTwister.DEGREE_OF_RECURRENCE) {
this.state[0] = this.state[_MersenneTwister.DEGREE_OF_RECURRENCE - 1];
return 1;
}

return i;
};

let i = 1,
j = 0,
k = _MersenneTwister.N > array.length ?
_MersenneTwister.N :
k = _MersenneTwister.DEGREE_OF_RECURRENCE > array.length ?
_MersenneTwister.DEGREE_OF_RECURRENCE :
array.length;

this._initWithSeed(19650218);

for (; k; k -= 1) {
const s = this.mt[i - 1] ^ (this.mt[i - 1] >>> 30);
const s = this.state[i - 1] ^ (this.state[i - 1] >>> 30);

this.mt[i] = (this.mt[i] ^ (((((s & 0xffff0000) >>> 16) * 1664525) << 16) + ((s & 0x0000ffff) * 1664525))) + array[j] + j;
this.mt[i] >>>= 0;
this.state[i] = (this.state[i] ^ (((((s & 0xffff0000) >>> 16) * 1664525) << 16) + ((s & 0x0000ffff) * 1664525))) + array[j] + j;
this.state[i] >>>= 0;

i += 1;
j += 1;

if (i >= _MersenneTwister.N) {
this.mt[0] = this.mt[_MersenneTwister.N - 1];
i = 1;
}
i = setAndResetBigI(i);

if (j >= array.length) {
j = 0;
}
}

for (k = _MersenneTwister.N - 1; k; k -= 1) {
const s = this.mt[i - 1] ^ (this.mt[i - 1] >>> 30);
for (k = _MersenneTwister.DEGREE_OF_RECURRENCE - 1; k; k -= 1) {
const s = this.state[i - 1] ^ (this.state[i - 1] >>> 30);

this.mt[i] = (this.mt[i] ^ (((((s & 0xffff0000) >>> 16) * 1566083941) << 16) + (s & 0x0000ffff) * 1566083941)) - i;
this.mt[i] >>>= 0;
this.state[i] = (this.state[i] ^ (((((s & 0xffff0000) >>> 16) * 1566083941) << 16) + (s & 0x0000ffff) * 1566083941)) - i;
this.state[i] >>>= 0;

i += 1;

if (i >= _MersenneTwister.N) {
this.mt[0] = this.mt[_MersenneTwister.N - 1];
i = 1;
}
i = setAndResetBigI(i);
}

this.mt[0] = 0x80000000;
this.state[0] = 0x80000000;
},

_initWithSeed (seed) {
this.mt[0] = seed >>> 0;
this.state[0] = seed >>> 0;

for (this.mtIndex = 1; this.mtIndex < _MersenneTwister.N; this.mtIndex += 1) {
const s = this.mt[this.mtIndex - 1] ^ (this.mt[this.mtIndex - 1] >>> 30);
for (this.stateIndex = 1; this.stateIndex < _MersenneTwister.DEGREE_OF_RECURRENCE; this.stateIndex += 1) {
const s = this.state[this.stateIndex - 1] ^ (this.state[this.stateIndex - 1] >>> 30);

this.mt[this.mtIndex] = (((((s & 0xffff0000) >>> 16) * 1812433253) << 16) + (s & 0x0000ffff) * 1812433253) + this.mtIndex;
this.mt[this.mtIndex] >>>= 0;
this.state[this.stateIndex] = (((((s & 0xffff0000) >>> 16) * 1812433253) << 16) + (s & 0x0000ffff) * 1812433253) + this.stateIndex;
this.state[this.stateIndex] >>>= 0;
}
}
}, {
DEGREE_OF_RECURRENCE: 624,
LOWER_MASK: 0x7fffffff, // Least significant R bits
M: 397,
MATRIX_A: 0x9908b0df, // Constant vector `a
N: 624,
MIDDLE_WORD: 397,
RATIONAL_NORMAL_FORM_TWIST_MATRIX: 0x9908b0df, // Constant vector `a
UPPER_MASK: 0x80000000 // Most significant W-R bits
});

Expand Down
44 changes: 22 additions & 22 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -111,5 +111,5 @@
"rebuild": "rm -rf ./node_modules && rm package-lock.json && npm install",
"test": "cross-env BABEL_ENV=test nyc mocha"
},
"version": "1.0.1"
"version": "1.0.2"
}

0 comments on commit ea5dffa

Please sign in to comment.