-
-
Notifications
You must be signed in to change notification settings - Fork 65
/
prng.js
200 lines (180 loc) · 5.94 KB
/
prng.js
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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
/**
* Fast Pseudo Random Number Generators.
*
* Given a seed a PRNG generates a sequence of numbers that cannot be reasonably predicted.
* Two PRNGs must generate the same random sequence of numbers if given the same seed.
*
* @module prng
*/
import * as binary from './binary.js'
import { fromCharCode, fromCodePoint } from './string.js'
import * as math from './math.js'
import { Xoroshiro128plus } from './prng/Xoroshiro128plus.js'
import * as buffer from './buffer.js'
/**
* Description of the function
* @callback generatorNext
* @return {number} A random float in the cange of [0,1)
*/
/**
* A random type generator.
*
* @typedef {Object} PRNG
* @property {generatorNext} next Generate new number
*/
export const DefaultPRNG = Xoroshiro128plus
/**
* Create a Xoroshiro128plus Pseudo-Random-Number-Generator.
* This is the fastest full-period generator passing BigCrush without systematic failures.
* But there are more PRNGs available in ./PRNG/.
*
* @param {number} seed A positive 32bit integer. Do not use negative numbers.
* @return {PRNG}
*/
export const create = seed => new DefaultPRNG(seed)
/**
* Generates a single random bool.
*
* @param {PRNG} gen A random number generator.
* @return {Boolean} A random boolean
*/
export const bool = gen => (gen.next() >= 0.5)
/**
* Generates a random integer with 53 bit resolution.
*
* @param {PRNG} gen A random number generator.
* @param {Number} min The lower bound of the allowed return values (inclusive).
* @param {Number} max The upper bound of the allowed return values (inclusive).
* @return {Number} A random integer on [min, max]
*/
export const int53 = (gen, min, max) => math.floor(gen.next() * (max + 1 - min) + min)
/**
* Generates a random integer with 53 bit resolution.
*
* @param {PRNG} gen A random number generator.
* @param {Number} min The lower bound of the allowed return values (inclusive).
* @param {Number} max The upper bound of the allowed return values (inclusive).
* @return {Number} A random integer on [min, max]
*/
export const uint53 = (gen, min, max) => math.abs(int53(gen, min, max))
/**
* Generates a random integer with 32 bit resolution.
*
* @param {PRNG} gen A random number generator.
* @param {Number} min The lower bound of the allowed return values (inclusive).
* @param {Number} max The upper bound of the allowed return values (inclusive).
* @return {Number} A random integer on [min, max]
*/
export const int32 = (gen, min, max) => math.floor(gen.next() * (max + 1 - min) + min)
/**
* Generates a random integer with 53 bit resolution.
*
* @param {PRNG} gen A random number generator.
* @param {Number} min The lower bound of the allowed return values (inclusive).
* @param {Number} max The upper bound of the allowed return values (inclusive).
* @return {Number} A random integer on [min, max]
*/
export const uint32 = (gen, min, max) => int32(gen, min, max) >>> 0
/**
* @deprecated
* Optimized version of prng.int32. It has the same precision as prng.int32, but should be preferred when
* openaring on smaller ranges.
*
* @param {PRNG} gen A random number generator.
* @param {Number} min The lower bound of the allowed return values (inclusive).
* @param {Number} max The upper bound of the allowed return values (inclusive). The max inclusive number is `binary.BITS31-1`
* @return {Number} A random integer on [min, max]
*/
export const int31 = (gen, min, max) => int32(gen, min, max)
/**
* Generates a random real on [0, 1) with 53 bit resolution.
*
* @param {PRNG} gen A random number generator.
* @return {Number} A random real number on [0, 1).
*/
export const real53 = gen => gen.next() // (((gen.next() >>> 5) * binary.BIT26) + (gen.next() >>> 6)) / MAX_SAFE_INTEGER
/**
* Generates a random character from char code 32 - 126. I.e. Characters, Numbers, special characters, and Space:
*
* @param {PRNG} gen A random number generator.
* @return {string}
*
* (Space)!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[/]^_`abcdefghijklmnopqrstuvwxyz{|}~
*/
export const char = gen => fromCharCode(int31(gen, 32, 126))
/**
* @param {PRNG} gen
* @return {string} A single letter (a-z)
*/
export const letter = gen => fromCharCode(int31(gen, 97, 122))
/**
* @param {PRNG} gen
* @param {number} [minLen=0]
* @param {number} [maxLen=20]
* @return {string} A random word (0-20 characters) without spaces consisting of letters (a-z)
*/
export const word = (gen, minLen = 0, maxLen = 20) => {
const len = int31(gen, minLen, maxLen)
let str = ''
for (let i = 0; i < len; i++) {
str += letter(gen)
}
return str
}
/**
* TODO: this function produces invalid runes. Does not cover all of utf16!!
*
* @param {PRNG} gen
* @return {string}
*/
export const utf16Rune = gen => {
const codepoint = int31(gen, 0, 256)
return fromCodePoint(codepoint)
}
/**
* @param {PRNG} gen
* @param {number} [maxlen = 20]
*/
export const utf16String = (gen, maxlen = 20) => {
const len = int31(gen, 0, maxlen)
let str = ''
for (let i = 0; i < len; i++) {
str += utf16Rune(gen)
}
return str
}
/**
* Returns one element of a given array.
*
* @param {PRNG} gen A random number generator.
* @param {Array<T>} array Non empty Array of possible values.
* @return {T} One of the values of the supplied Array.
* @template T
*/
export const oneOf = (gen, array) => array[int31(gen, 0, array.length - 1)]
/**
* @param {PRNG} gen
* @param {number} len
* @return {Uint8Array}
*/
export const uint8Array = (gen, len) => {
const buf = buffer.createUint8ArrayFromLen(len)
for (let i = 0; i < buf.length; i++) {
buf[i] = int32(gen, 0, binary.BITS8)
}
return buf
}
/* c8 ignore start */
/**
* @param {PRNG} gen
* @param {number} len
* @return {Uint16Array}
*/
export const uint16Array = (gen, len) => new Uint16Array(uint8Array(gen, len * 2).buffer)
/**
* @param {PRNG} gen
* @param {number} len
* @return {Uint32Array}
*/
export const uint32Array = (gen, len) => new Uint32Array(uint8Array(gen, len * 4).buffer)
/* c8 ignore stop */