From 8f6f776223d6340bfa8893aa3c19a22887562cb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Ooms?= Date: Tue, 8 Dec 2020 23:17:32 +0100 Subject: [PATCH] :boom: BREAKING CHANGE: Add fill method. Renamed `nextFloat` to `nextFloat64`. See #1. --- README.md | 4 +- src/_fill.js | 7 +++ src/fill.js | 65 ++++++++++++++++++++++++++++ src/index.js | 8 ++-- src/nextBigInt64.js | 5 +++ src/nextBigUint64.js | 5 +++ src/nextFloat32.js | 4 ++ src/{nextFloat.js => nextFloat64.js} | 2 +- src/nextUint16.js | 3 ++ src/nextUint8.js | 3 ++ test/src/splitmix64.js | 4 +- test/src/xoroshiro128plus.js | 11 +++-- 12 files changed, 107 insertions(+), 14 deletions(-) create mode 100644 src/_fill.js create mode 100644 src/fill.js create mode 100644 src/nextBigInt64.js create mode 100644 src/nextBigUint64.js create mode 100644 src/nextFloat32.js rename src/{nextFloat.js => nextFloat64.js} (71%) create mode 100644 src/nextUint16.js create mode 100644 src/nextUint8.js diff --git a/README.md b/README.md index 8b1625d..dfd5b16 100644 --- a/README.md +++ b/README.md @@ -9,14 +9,14 @@ See [docs](https://aureooms.github.io/js-pseudo-random/index.html). ```js import { splitmix64, - nextFloat, + nextFloat64, nextUint64, } from '@aureooms/js-pseudo-random'; const seed = [0, 0]; // Two 32-bit signed integers. const prng = splitmix64(seed); nextUint64(prng); // 64 random bits as two 32-bit signed integers (compatible with @aureooms/js-uint64). -nextFloat(prng); // A random float in the range [0, 1[. +nextFloat64(prng); // A random double in the range [0, 1[. ``` [![License](https://img.shields.io/github/license/aureooms/js-pseudo-random.svg)](https://raw.githubusercontent.com/aureooms/js-pseudo-random/main/LICENSE) diff --git a/src/_fill.js b/src/_fill.js new file mode 100644 index 0000000..40d2dd8 --- /dev/null +++ b/src/_fill.js @@ -0,0 +1,7 @@ +const _fill = (next, prng, array, i = 0, j = array.length) => { + for (; i < j; ++i) { + array[i] = next(prng); + } +}; + +export default _fill; diff --git a/src/fill.js b/src/fill.js new file mode 100644 index 0000000..a205a54 --- /dev/null +++ b/src/fill.js @@ -0,0 +1,65 @@ +import _fill from './_fill'; +import nextUint8 from './nextUint8'; +import nextUint16 from './nextUint16'; +import nextInt32 from './nextInt32'; +import nextFloat32 from './nextFloat32'; +import nextFloat64 from './nextFloat64'; +import nextBigInt64 from './nextBigInt64'; +import nextBigUint64 from './nextBigUint64'; + +const fill = (prng, array, i, j) => { + switch (array.constructor) { + case ArrayBuffer: + return _fill(nextUint8, new Uint8Array(array), i, j); + + case Int8Array: + case Uint8Array: + case Uint8ClampedArray: + return _fill( + nextUint8, + prng, + new Uint8Array(array.buffer, array.byteOffset, array.byteLength), + i, + j, + ); + + case Int16Array: + case Uint16Array: + return _fill( + nextUint16, + prng, + new Uint16Array(array.buffer, array.byteOffset, array.length), + i, + j, + ); + + case Int32Array: + case Uint32Array: + return _fill( + nextInt32, + prng, + new Int32Array(array.buffer, array.byteOffset, array.length), + i, + j, + ); + + case Float32Array: + return _fill(nextFloat32, prng, array, i, j); + + case Float64Array: + return _fill(nextFloat64, prng, array, i, j); + + case BigInt64Array: + return _fill(nextBigInt64, prng, array, i, j); + + case BigUint64Array: + return _fill(nextBigUint64, prng, array, i, j); + + default: + throw new Error( + `fill(prng, array, ...): array with constructor '${array.constructor.name}' not implemented`, + ); + } +}; + +export default fill; diff --git a/src/index.js b/src/index.js index 7833d25..476620b 100644 --- a/src/index.js +++ b/src/index.js @@ -1,4 +1,5 @@ -import nextFloat from './nextFloat'; +import fill from './fill'; +import nextFloat64 from './nextFloat64'; import nextInt32 from './nextInt32'; import nextUint64 from './nextUint64'; import splitmix64 from './splitmix64'; @@ -6,11 +7,12 @@ import xoroshiro128plus from './xoroshiro128plus'; /* eslint import/no-anonymous-default-export: [2, {"allowObject": true}] */ export default { - nextFloat, + fill, + nextFloat64, nextInt32, nextUint64, splitmix64, xoroshiro128plus, }; -export {nextFloat, nextInt32, nextUint64, splitmix64, xoroshiro128plus}; +export {fill, nextFloat64, nextInt32, nextUint64, splitmix64, xoroshiro128plus}; diff --git a/src/nextBigInt64.js b/src/nextBigInt64.js new file mode 100644 index 0000000..b8b2ce1 --- /dev/null +++ b/src/nextBigInt64.js @@ -0,0 +1,5 @@ +import nextBigUint64 from './nextBigUint64'; + +export default function nextBigInt64(prng) { + return nextBigUint64(prng) - BigInt(2 ** 63); +} diff --git a/src/nextBigUint64.js b/src/nextBigUint64.js new file mode 100644 index 0000000..21c4c5b --- /dev/null +++ b/src/nextBigUint64.js @@ -0,0 +1,5 @@ +export default function nextBigUint64(prng) { + const a = prng.next().value; + const b = prng.next().value; + return BigInt(a) * BigInt(2 ** 32) + BigInt(b); +} diff --git a/src/nextFloat32.js b/src/nextFloat32.js new file mode 100644 index 0000000..a67b699 --- /dev/null +++ b/src/nextFloat32.js @@ -0,0 +1,4 @@ +export default function nextFloat32(prng) { + const x = prng.next().value; + return (x >>> 9) / 2 ** 23; +} diff --git a/src/nextFloat.js b/src/nextFloat64.js similarity index 71% rename from src/nextFloat.js rename to src/nextFloat64.js index 90e33c9..4d3f87a 100644 --- a/src/nextFloat.js +++ b/src/nextFloat64.js @@ -1,4 +1,4 @@ -export default function nextFloat(prng) { +export default function nextFloat64(prng) { const a = prng.next().value; const b = prng.next().value; return (a >>> 0) / 2 ** 32 + (b >>> 0) / 2 ** 64; diff --git a/src/nextUint16.js b/src/nextUint16.js new file mode 100644 index 0000000..9a7f81c --- /dev/null +++ b/src/nextUint16.js @@ -0,0 +1,3 @@ +export default function nextUint16(prng) { + return (prng.next().value >>> 16) & 0xffff; +} diff --git a/src/nextUint8.js b/src/nextUint8.js new file mode 100644 index 0000000..bc48e5f --- /dev/null +++ b/src/nextUint8.js @@ -0,0 +1,3 @@ +export default function nextUint8(prng) { + return (prng.next().value >>> 24) & 0xff; +} diff --git a/test/src/splitmix64.js b/test/src/splitmix64.js index 04dcaed..6f73c01 100644 --- a/test/src/splitmix64.js +++ b/test/src/splitmix64.js @@ -2,7 +2,7 @@ import test from 'ava'; import {range, map} from '@aureooms/js-itertools'; import {get64} from '@aureooms/js-uint64'; -import {splitmix64, nextUint64, nextFloat} from '../../src'; +import {splitmix64, nextUint64, nextFloat64} from '../../src'; test('https://rosettacode.org/wiki/Pseudo-random_numbers/Splitmix64 #1', (t) => { /** @@ -29,7 +29,7 @@ test('https://rosettacode.org/wiki/Pseudo-random_numbers/Splitmix64 #2', (t) => const prng = splitmix64(seed); const histogram = new Array(5).fill(0); for (const k of map( - () => Math.floor(nextFloat(prng) * 5) | 0, + () => Math.floor(nextFloat64(prng) * 5) | 0, range(100000), )) { ++histogram[k]; diff --git a/test/src/xoroshiro128plus.js b/test/src/xoroshiro128plus.js index 0ea7d77..f102edf 100644 --- a/test/src/xoroshiro128plus.js +++ b/test/src/xoroshiro128plus.js @@ -2,7 +2,7 @@ import test from 'ava'; import {get64} from '@aureooms/js-uint64'; -import {splitmix64, xoroshiro128plus, nextInt32, nextUint64} from '../../src'; +import {splitmix64, xoroshiro128plus, fill, nextUint64} from '../../src'; test('Example found at https://github.com/dgryski/go-xoroshiro/blob/ea5ca0291510c1f8b16321d610ae73e1006d499f/xoro_test.go#L28', (t) => { const prng = xoroshiro128plus([0, 1, 0, 2], {a: 55, b: 14, c: 36}); @@ -53,12 +53,11 @@ test('Example found at https://github.com/dgryski/go-xoroshiro/blob/ea5ca0291510 }); test('Example found at https://github.com/dgryski/go-xoroshiro/blob/ea5ca0291510c1f8b16321d610ae73e1006d499f/xoro_test.go#L80', (t) => { - const seed = splitmix64([0x0ddc0ffe, 0xebadf00d]); + const seeder = splitmix64([0x0ddc0ffe, 0xebadf00d]); + const seed = new Int32Array(4); + fill(seeder, seed); - const prng = xoroshiro128plus( - [nextInt32(seed), nextInt32(seed), nextInt32(seed), nextInt32(seed)], - {a: 55, b: 14, c: 36}, - ); + const prng = xoroshiro128plus(seed, {a: 55, b: 14, c: 36}); t.deepEqual(nextUint64(prng), get64(0xa3f4ee8f, 0x1df50a08)); // 11814330020949985800 t.deepEqual(nextUint64(prng), get64(0xa3febba4, 0x5a9ce9c5)); // 11817088786836023749