UNPKG

fast-prng-wasm

Version:

A collection of fast, SIMD-enabled, pseudo random number generators in WebAssembly. Simple to use from JavaScript (node or browser), and AssemblyScript.

157 lines (126 loc) 4.38 kB
import { int53Number, number, coord, coordSquared } from './common'; const MULTIPLIER: u64 = 6364136223846793005; // In PCG, unique increment provides a unique stream. // This number must ALWAYS BE ODD! let increment: u64 = 1442695040888963407; let state: u64 = 0; export const SEED_COUNT: i32 = 1; export function setSeed(seed: u64): void { state = seed; nextInt32(); } /** * Choose the unique stream to be provided by this generator. * @param inc Any integer, provided it is unique amongst stream increments * used for other generator instances, if you want them to remain unique. */ export function setStreamIncrement(inc: u64): void { // ensure the increment is odd regardless of value given increment = (inc << 1) | 1; // advance state nextInt32(); } /** * Main PCG state advancement / generator function. * @returns This generator's next unsigned 32-bit integer. */ @inline export function nextInt32(): u32 { const oldState: u64 = state; state = oldState * MULTIPLIER + increment; // Calculate output function (XSH RR) const xorshifted: u32 = <u32>(((oldState >> 18) ^ oldState) >> 27); const rot: u32 = <u32>(oldState >> 59); return (xorshifted >> rot) | (xorshifted << (-rot & 31)); } // No runtime function call penalty is incurred by chaining these functions, // because we inline them and optimize the build at compile time /** * Chain two u32s together to get a u64. * @returns This generator's next unsigned 64-bit integer. */ @inline export function nextInt64(): u64 { return (<u64>nextInt32() << 32) | <u64>nextInt32(); } @inline export function nextInt53Number(): f64 { return int53Number(nextInt64()); } @inline export function nextInt32Number(): f64 { return <f64>nextInt32(); } @inline export function nextNumber(): f64 { return number(nextInt64()); } @inline export function nextCoord(): f64 { return coord(nextInt64()); } @inline export function nextCoordSquared(): f64 { return coordSquared(nextInt64()); } // Expose array management functions from this module export { allocUint64Array, allocFloat64Array, freeArray } from './common'; /* * If we extract the following mostly-repeated functions to shared logic, * define a type for the function, and pass the generator function as a * parameter, it runs somewhat slower because of runtime function call overhead * (At least I think, and so it can't be avoided using @inline). * * So in the interest of speed over cleanliness, we repeat this logic in each * generator type. * * The same speed caveat applies when wrapping the generators in a class: * Everything slows down. So we opt instead for static functions and speed. */ /** Monte Carlo test: Count how many random points fall inside a unit circle */ export function batchTestUnitCirclePoints(count: i32): i32 { let inCircle: i32 = 0; let xSquared: f64; let ySquared: f64; for (let i: i32 = 0; i < count; i++) { xSquared = nextCoordSquared(); ySquared = nextCoordSquared(); if (xSquared + ySquared <= 1.0) { inCircle++; } } return inCircle; } /* * Array Fill Functions */ export function fillUint64Array_Int64(arr: Uint64Array): void { for (let i: i32 = 0; i < arr.length; i++) { unchecked(arr[i] = nextInt64()); } } export function fillFloat64Array_Int53Numbers(arr: Float64Array): void { for (let i: i32 = 0; i < arr.length; i++) { unchecked(arr[i] = nextInt53Number()); } } export function fillFloat64Array_Int32Numbers(arr: Float64Array): void { for (let i: i32 = 0; i < arr.length; i++) { unchecked(arr[i] = nextInt32Number()); } } export function fillFloat64Array_Numbers(arr: Float64Array): void { for (let i: i32 = 0; i < arr.length; i++) { unchecked(arr[i] = nextNumber()); } } export function fillFloat64Array_Coords(arr: Float64Array): void { for (let i: i32 = 0; i < arr.length; i++) { unchecked(arr[i] = nextCoord()); } } export function fillFloat64Array_CoordsSquared(arr: Float64Array): void { for (let i: i32 = 0; i < arr.length; i++) { unchecked(arr[i] = nextCoordSquared()); } }