lib0
Version:
> Monorepo of isomorphic utility functions
388 lines (351 loc) • 10.8 kB
JavaScript
'use strict';
var binary = require('./binary-ac8e39e2.cjs');
var string = require('./string-6d104757.cjs');
var math = require('./math-08e068f9.cjs');
var encoding = require('./buffer-bc255c75.cjs');
/**
* @module prng
*/
/**
* Xorshift32 is a very simple but elegang PRNG with a period of `2^32-1`.
*/
class Xorshift32 {
/**
* @param {number} seed Unsigned 32 bit number
*/
constructor (seed) {
this.seed = seed;
/**
* @type {number}
*/
this._state = seed;
}
/**
* Generate a random signed integer.
*
* @return {Number} A 32 bit signed integer.
*/
next () {
let x = this._state;
x ^= x << 13;
x ^= x >> 17;
x ^= x << 5;
this._state = x;
return (x >>> 0) / (binary.BITS32 + 1)
}
}
/**
* @module prng
*/
/**
* This is a variant of xoroshiro128plus - the fastest full-period generator passing BigCrush without systematic failures.
*
* This implementation follows the idea of the original xoroshiro128plus implementation,
* but is optimized for the JavaScript runtime. I.e.
* * The operations are performed on 32bit integers (the original implementation works with 64bit values).
* * The initial 128bit state is computed based on a 32bit seed and Xorshift32.
* * This implementation returns two 32bit values based on the 64bit value that is computed by xoroshiro128plus.
* Caution: The last addition step works slightly different than in the original implementation - the add carry of the
* first 32bit addition is not carried over to the last 32bit.
*
* [Reference implementation](http://vigna.di.unimi.it/xorshift/xoroshiro128plus.c)
*/
class Xoroshiro128plus {
/**
* @param {number} seed Unsigned 32 bit number
*/
constructor (seed) {
this.seed = seed;
// This is a variant of Xoroshiro128plus to fill the initial state
const xorshift32 = new Xorshift32(seed);
this.state = new Uint32Array(4);
for (let i = 0; i < 4; i++) {
this.state[i] = xorshift32.next() * binary.BITS32;
}
this._fresh = true;
}
/**
* @return {number} Float/Double in [0,1)
*/
next () {
const state = this.state;
if (this._fresh) {
this._fresh = false;
return ((state[0] + state[2]) >>> 0) / (binary.BITS32 + 1)
} else {
this._fresh = true;
const s0 = state[0];
const s1 = state[1];
const s2 = state[2] ^ s0;
const s3 = state[3] ^ s1;
// function js_rotl (x, k) {
// k = k - 32
// const x1 = x[0]
// const x2 = x[1]
// x[0] = x2 << k | x1 >>> (32 - k)
// x[1] = x1 << k | x2 >>> (32 - k)
// }
// rotl(s0, 55) // k = 23 = 55 - 32; j = 9 = 32 - 23
state[0] = (s1 << 23 | s0 >>> 9) ^ s2 ^ (s2 << 14 | s3 >>> 18);
state[1] = (s0 << 23 | s1 >>> 9) ^ s3 ^ (s3 << 14);
// rol(s1, 36) // k = 4 = 36 - 32; j = 23 = 32 - 9
state[2] = s3 << 4 | s2 >>> 28;
state[3] = s2 << 4 | s3 >>> 28;
return (((state[1] + state[3]) >>> 0) / (binary.BITS32 + 1))
}
}
}
/*
// Reference implementation
// Source: http://vigna.di.unimi.it/xorshift/xoroshiro128plus.c
// By David Blackman and Sebastiano Vigna
// Who published the reference implementation under Public Domain (CC0)
#include <stdint.h>
#include <stdio.h>
uint64_t s[2];
static inline uint64_t rotl(const uint64_t x, int k) {
return (x << k) | (x >> (64 - k));
}
uint64_t next(void) {
const uint64_t s0 = s[0];
uint64_t s1 = s[1];
s1 ^= s0;
s[0] = rotl(s0, 55) ^ s1 ^ (s1 << 14); // a, b
s[1] = rotl(s1, 36); // c
return (s[0] + s[1]) & 0xFFFFFFFF;
}
int main(void)
{
int i;
s[0] = 1111 | (1337ul << 32);
s[1] = 1234 | (9999ul << 32);
printf("1000 outputs of genrand_int31()\n");
for (i=0; i<100; i++) {
printf("%10lu ", i);
printf("%10lu ", next());
printf("- %10lu ", s[0] >> 32);
printf("%10lu ", (s[0] << 32) >> 32);
printf("%10lu ", s[1] >> 32);
printf("%10lu ", (s[1] << 32) >> 32);
printf("\n");
// if (i%5==4) printf("\n");
}
return 0;
}
*/
/**
* 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
*/
/**
* 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
*/
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}
*/
const create = seed => new DefaultPRNG(seed);
/**
* Generates a single random bool.
*
* @param {PRNG} gen A random number generator.
* @return {Boolean} A random boolean
*/
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]
*/
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]
*/
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]
*/
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]
*/
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]
*/
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).
*/
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{|}~
*/
const char = gen => string.fromCharCode(int31(gen, 32, 126));
/**
* @param {PRNG} gen
* @return {string} A single letter (a-z)
*/
const letter = gen => string.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)
*/
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}
*/
const utf16Rune = gen => {
const codepoint = int31(gen, 0, 256);
return string.fromCodePoint(codepoint)
};
/**
* @param {PRNG} gen
* @param {number} [maxlen = 20]
*/
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
*/
const oneOf = (gen, array) => array[int31(gen, 0, array.length - 1)];
/**
* @param {PRNG} gen
* @param {number} len
* @return {Uint8Array}
*/
const uint8Array = (gen, len) => {
const buf = encoding.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}
*/
const uint16Array = (gen, len) => new Uint16Array(uint8Array(gen, len * 2).buffer);
/**
* @param {PRNG} gen
* @param {number} len
* @return {Uint32Array}
*/
const uint32Array = (gen, len) => new Uint32Array(uint8Array(gen, len * 4).buffer);
/* c8 ignore stop */
var prng = /*#__PURE__*/Object.freeze({
__proto__: null,
DefaultPRNG: DefaultPRNG,
create: create,
bool: bool,
int53: int53,
uint53: uint53,
int32: int32,
uint32: uint32,
int31: int31,
real53: real53,
char: char,
letter: letter,
word: word,
utf16Rune: utf16Rune,
utf16String: utf16String,
oneOf: oneOf,
uint8Array: uint8Array,
uint16Array: uint16Array,
uint32Array: uint32Array
});
exports.DefaultPRNG = DefaultPRNG;
exports.bool = bool;
exports.char = char;
exports.create = create;
exports.int31 = int31;
exports.int32 = int32;
exports.int53 = int53;
exports.letter = letter;
exports.oneOf = oneOf;
exports.prng = prng;
exports.real53 = real53;
exports.uint16Array = uint16Array;
exports.uint32 = uint32;
exports.uint32Array = uint32Array;
exports.uint53 = uint53;
exports.uint8Array = uint8Array;
exports.utf16Rune = utf16Rune;
exports.utf16String = utf16String;
exports.word = word;
//# sourceMappingURL=prng-d6655349.cjs.map