UNPKG

6.08 kBJavaScriptView Raw
1/**
2 * Fast Pseudo Random Number Generators.
3 *
4 * Given a seed a PRNG generates a sequence of numbers that cannot be reasonably predicted.
5 * Two PRNGs must generate the same random sequence of numbers if given the same seed.
6 *
7 * @module prng
8 */
9
10import * as binary from './binary.js'
11import { fromCharCode, fromCodePoint } from './string.js'
12import * as math from './math.js'
13import { Xoroshiro128plus } from './prng/Xoroshiro128plus.js'
14import * as buffer from './buffer.js'
15
16/**
17 * Description of the function
18 * @callback generatorNext
19 * @return {number} A random float in the cange of [0,1)
20 */
21
22/**
23 * A random type generator.
24 *
25 * @typedef {Object} PRNG
26 * @property {generatorNext} next Generate new number
27 */
28export const DefaultPRNG = Xoroshiro128plus
29
30/**
31 * Create a Xoroshiro128plus Pseudo-Random-Number-Generator.
32 * This is the fastest full-period generator passing BigCrush without systematic failures.
33 * But there are more PRNGs available in ./PRNG/.
34 *
35 * @param {number} seed A positive 32bit integer. Do not use negative numbers.
36 * @return {PRNG}
37 */
38export const create = seed => new DefaultPRNG(seed)
39
40/**
41 * Generates a single random bool.
42 *
43 * @param {PRNG} gen A random number generator.
44 * @return {Boolean} A random boolean
45 */
46export const bool = gen => (gen.next() >= 0.5)
47
48/**
49 * Generates a random integer with 53 bit resolution.
50 *
51 * @param {PRNG} gen A random number generator.
52 * @param {Number} min The lower bound of the allowed return values (inclusive).
53 * @param {Number} max The upper bound of the allowed return values (inclusive).
54 * @return {Number} A random integer on [min, max]
55 */
56export const int53 = (gen, min, max) => math.floor(gen.next() * (max + 1 - min) + min)
57
58/**
59 * Generates a random integer with 53 bit resolution.
60 *
61 * @param {PRNG} gen A random number generator.
62 * @param {Number} min The lower bound of the allowed return values (inclusive).
63 * @param {Number} max The upper bound of the allowed return values (inclusive).
64 * @return {Number} A random integer on [min, max]
65 */
66export const uint53 = (gen, min, max) => math.abs(int53(gen, min, max))
67
68/**
69 * Generates a random integer with 32 bit resolution.
70 *
71 * @param {PRNG} gen A random number generator.
72 * @param {Number} min The lower bound of the allowed return values (inclusive).
73 * @param {Number} max The upper bound of the allowed return values (inclusive).
74 * @return {Number} A random integer on [min, max]
75 */
76export const int32 = (gen, min, max) => math.floor(gen.next() * (max + 1 - min) + min)
77
78/**
79 * Generates a random integer with 53 bit resolution.
80 *
81 * @param {PRNG} gen A random number generator.
82 * @param {Number} min The lower bound of the allowed return values (inclusive).
83 * @param {Number} max The upper bound of the allowed return values (inclusive).
84 * @return {Number} A random integer on [min, max]
85 */
86export const uint32 = (gen, min, max) => int32(gen, min, max) >>> 0
87
88/**
89 * @deprecated
90 * Optimized version of prng.int32. It has the same precision as prng.int32, but should be preferred when
91 * openaring on smaller ranges.
92 *
93 * @param {PRNG} gen A random number generator.
94 * @param {Number} min The lower bound of the allowed return values (inclusive).
95 * @param {Number} max The upper bound of the allowed return values (inclusive). The max inclusive number is `binary.BITS31-1`
96 * @return {Number} A random integer on [min, max]
97 */
98export const int31 = (gen, min, max) => int32(gen, min, max)
99
100/**
101 * Generates a random real on [0, 1) with 53 bit resolution.
102 *
103 * @param {PRNG} gen A random number generator.
104 * @return {Number} A random real number on [0, 1).
105 */
106export const real53 = gen => gen.next() // (((gen.next() >>> 5) * binary.BIT26) + (gen.next() >>> 6)) / MAX_SAFE_INTEGER
107
108/**
109 * Generates a random character from char code 32 - 126. I.e. Characters, Numbers, special characters, and Space:
110 *
111 * @param {PRNG} gen A random number generator.
112 * @return {string}
113 *
114 * (Space)!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[/]^_`abcdefghijklmnopqrstuvwxyz{|}~
115 */
116export const char = gen => fromCharCode(int31(gen, 32, 126))
117
118/**
119 * @param {PRNG} gen
120 * @return {string} A single letter (a-z)
121 */
122export const letter = gen => fromCharCode(int31(gen, 97, 122))
123
124/**
125 * @param {PRNG} gen
126 * @param {number} [minLen=0]
127 * @param {number} [maxLen=20]
128 * @return {string} A random word (0-20 characters) without spaces consisting of letters (a-z)
129 */
130export const word = (gen, minLen = 0, maxLen = 20) => {
131 const len = int31(gen, minLen, maxLen)
132 let str = ''
133 for (let i = 0; i < len; i++) {
134 str += letter(gen)
135 }
136 return str
137}
138
139/**
140 * TODO: this function produces invalid runes. Does not cover all of utf16!!
141 *
142 * @param {PRNG} gen
143 * @return {string}
144 */
145export const utf16Rune = gen => {
146 const codepoint = int31(gen, 0, 256)
147 return fromCodePoint(codepoint)
148}
149
150/**
151 * @param {PRNG} gen
152 * @param {number} [maxlen = 20]
153 */
154export const utf16String = (gen, maxlen = 20) => {
155 const len = int31(gen, 0, maxlen)
156 let str = ''
157 for (let i = 0; i < len; i++) {
158 str += utf16Rune(gen)
159 }
160 return str
161}
162
163/**
164 * Returns one element of a given array.
165 *
166 * @param {PRNG} gen A random number generator.
167 * @param {Array<T>} array Non empty Array of possible values.
168 * @return {T} One of the values of the supplied Array.
169 * @template T
170 */
171export const oneOf = (gen, array) => array[int31(gen, 0, array.length - 1)]
172
173/**
174 * @param {PRNG} gen
175 * @param {number} len
176 * @return {Uint8Array}
177 */
178export const uint8Array = (gen, len) => {
179 const buf = buffer.createUint8ArrayFromLen(len)
180 for (let i = 0; i < buf.length; i++) {
181 buf[i] = int32(gen, 0, binary.BITS8)
182 }
183 return buf
184}
185
186/* c8 ignore start */
187/**
188 * @param {PRNG} gen
189 * @param {number} len
190 * @return {Uint16Array}
191 */
192export const uint16Array = (gen, len) => new Uint16Array(uint8Array(gen, len * 2).buffer)
193
194/**
195 * @param {PRNG} gen
196 * @param {number} len
197 * @return {Uint32Array}
198 */
199export const uint32Array = (gen, len) => new Uint32Array(uint8Array(gen, len * 4).buffer)
200/* c8 ignore stop */