-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.ts
More file actions
112 lines (100 loc) · 3.8 KB
/
index.ts
File metadata and controls
112 lines (100 loc) · 3.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
/**
* Copyright 2014 - 2021 George MacKerron
* Released under the MIT Licence: http://opensource.org/licenses/MIT
*/
/**
* Mersenne Twister drop-in replacement for Math.random,
* including the 2002 improvements to initialization.
*/
export default class MTwist {
private mt: number[];
private mti: number;
/**
* Pass a seed value for reproducible sequences, which are the main reason to
* use this library over plain Math.random()
* @param seed An integer between 0 and 4294967295
*/
constructor(seed = Math.random() * 4294967295) { // seed with a 32-bit integer
this.mt = new Array(624);
this.mt[0] = seed >>> 0;
const n1 = 1812433253;
for (let mti = 1; mti < 624; mti++) {
const n2 = this.mt[mti - 1] ^ (this.mt[mti - 1] >>> 30);
// uint32 multiplication, low 16 bits and high 16 bits multiplied separately and reassembled:
this.mt[mti] = ((((n1 & 0xffff0000) * n2) >>> 0) + (((n1 & 0x0000ffff) * n2) >>> 0) + mti) >>> 0;
}
this.mti = 624;
}
/**
* Returns an integer in the interval [0,0xffffffff]
*/
randomUInt32() { // [0,0xffffffff]
let y;
if (this.mti >= 624) {
for (let i = 0; i < 227; i++) {
y = ((this.mt[i] & 0x80000000) | (this.mt[i + 1] & 0x7fffffff)) >>> 0;
this.mt[i] = (this.mt[i + 397] ^ (y >>> 1) ^ (y & 1 ? 0x9908b0df : 0)) >>> 0;
}
for (let i = 227; i < 623; i++) {
y = ((this.mt[i] & 0x80000000) | (this.mt[i + 1] & 0x7fffffff)) >>> 0;
this.mt[i] = (this.mt[i - 227] ^ (y >>> 1) ^ (y & 1 ? 0x9908b0df : 0)) >>> 0;
}
y = ((this.mt[623] & 0x80000000) | (this.mt[0] & 0x7fffffff)) >>> 0;
this.mt[623] = (this.mt[396] ^ (y >>> 1) ^ (y & 1 ? 0x9908b0df : 0)) >>> 0;
this.mti = 0;
}
y = this.mt[this.mti++];
y = (y ^ (y >>> 11)) >>> 0;
y = (y ^ ((y << 7) & 0x9d2c5680)) >>> 0;
y = (y ^ ((y << 15) & 0xefc60000)) >>> 0;
y = (y ^ (y >>> 18)) >>> 0;
return y;
}
/**
* Returns a fractional number in the interval [0,1), just like Math.random
*/
random() { // [0,1), like Math.random
return this.randomUInt32() / 4294967296; // 2^32
}
/**
* Returns an integer in the interval [0,n) with proper uniform distribution
* [see WARNING](http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/efaq.html)
* @param maxPlusOne The integer returned will be less than this value
*/
randomIntBelow(maxPlusOne: number) {
if (maxPlusOne < 1) throw new Error("Upper bound must be greater than or equal to 1");
if (maxPlusOne > 4294967296) throw new Error("Upper bound must not be greater than 4294967296");
if (maxPlusOne === 1) return 0;
const
bitsNeeded = Math.ceil(Math.log2(maxPlusOne)),
bitMask = (1 << bitsNeeded) - 1;
while (true) {
const int = this.randomUInt32() & bitMask;
if (int < maxPlusOne) return int;
}
}
/**
* Returns an integer in the interval [m,n] with proper uniform distribution
* [see WARNING](http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/efaq.html)
* @param inclusiveMin The integer returned will be no lower than this value
* @param inclusiveMax The integer returned will be no higher than this value
*/
randomIntBetween(inclusiveMin: number, inclusiveMax: number) { // [m,n]
return inclusiveMin + this.randomIntBelow(inclusiveMax - inclusiveMin + 1);
}
/**
* Returns true if test calculations match those from the official C code
*/
static test() {
const iterationFactor = 10000; // makes max iterations about 400,000
let seed = 3234567890;
for (let i = 0; i < 1000; i++) {
const
mtwist = new MTwist(seed),
iterations = Math.floor(mtwist.randomUInt32() / iterationFactor);
for (let j = 0; j < iterations; j++) mtwist.randomUInt32();
seed = mtwist.randomUInt32();
}
return seed === 1061063157;
}
}