diff --git a/src/__tests__/createPcg32.test.ts b/src/__tests__/createPcg32.test.ts index 17f24a4..a8a8b85 100644 --- a/src/__tests__/createPcg32.test.ts +++ b/src/__tests__/createPcg32.test.ts @@ -1,4 +1,5 @@ import { createPcg32, nextState, prevState, randomInt, randomList } from '..' +import { OutputFnType } from '../types' describe('basic', () => { it('pCG32_XSH_RR: Single integer', () => { @@ -11,6 +12,36 @@ describe('basic', () => { expect(randomUint32(pcg)[0]).toBe(0xa15c02b7) }) + it('pCG32_XSH_RS: Single integer', () => { + expect.assertions(2) + const randomUint32 = randomInt(0, 2 ** 32 - 1) + const pcg = createPcg32({ outputFnType: OutputFnType.XSH_RS }, 42, 54) + // Check for generator immutability and result reproducibility + const [n, _state] = randomUint32(pcg) + expect(n).toBe(1545299392) + expect(randomUint32(pcg)[0]).toBe(1545299392) + }) + + it('pCG32_XSL_RR: Single integer', () => { + expect.assertions(2) + const randomUint32 = randomInt(0, 2 ** 32 - 1) + const pcg = createPcg32({ outputFnType: OutputFnType.XSL_RR }, 42, 54) + // Check for generator immutability and result reproducibility + const [n, _state] = randomUint32(pcg) + expect(n).toBe(110043304) + expect(randomUint32(pcg)[0]).toBe(110043304) + }) + + it('pCG32_RXS_M_XS: Single integer', () => { + expect.assertions(2) + const randomUint32 = randomInt(0, 2 ** 32 - 1) + const pcg = createPcg32({ outputFnType: OutputFnType.RXS_M_XS }, 42, 54) + // Check for generator immutability and result reproducibility + const [n, _state] = randomUint32(pcg) + expect(n).toBe(3562606574) + expect(randomUint32(pcg)[0]).toBe(3562606574) + }) + it('pCG32_XSH_RR: Multiple integers', () => { expect.assertions(1) const randomUint32 = randomInt(0, 2 ** 32 - 1) @@ -20,6 +51,33 @@ describe('basic', () => { ]) }) + it('pCG32_XSH_RS: Multiple integers', () => { + expect.assertions(1) + const randomUint32 = randomInt(0, 2 ** 32 - 1) + const pcg = createPcg32({ outputFnType: OutputFnType.XSH_RS }, 42, 54) + expect(randomList(6, randomUint32, pcg).map(([value]) => value)).toStrictEqual([ + 1545299392, 2415717169, 3435843701, 3090997190, 1576856010, 3235194092, + ]) + }) + + it('pCG32_XSL_RR: Multiple integers', () => { + expect.assertions(1) + const randomUint32 = randomInt(0, 2 ** 32 - 1) + const pcg = createPcg32({ outputFnType: OutputFnType.XSL_RR }, 42, 54) + expect(randomList(6, randomUint32, pcg).map(([value]) => value)).toStrictEqual([ + 110043304, 3982559790, 957466950, 3645676572, 223035418, 2465086851, + ]) + }) + + it('pCG32_RXS_M_XS: Multiple integers', () => { + expect.assertions(1) + const randomUint32 = randomInt(0, 2 ** 32 - 1) + const pcg = createPcg32({ outputFnType: OutputFnType.RXS_M_XS }, 42, 54) + expect(randomList(6, randomUint32, pcg).map(([value]) => value)).toStrictEqual([ + 3562606574, 3701842622, 2826130885, 1212371962, 849807893, 1843984456, + ]) + }) + it('pCG32_XSH_RR: Jump-ahead, jump-back', () => { expect.assertions(5) const randomUint32 = randomInt(0, 2 ** 32 - 1) diff --git a/src/createPcg.ts b/src/createPcg.ts index 619f14b..98a2de4 100644 --- a/src/createPcg.ts +++ b/src/createPcg.ts @@ -67,8 +67,8 @@ export const randomInt = curry((min: number, max: number, pcg: PCGState): [numbe return [n.mod(bound).add(min).toNumber(), nextPcg] }) -export const randomList = curry((length, rng, pcg): [number, PCGState][] => - scan(([, nextPcg]) => rng(nextPcg), rng(pcg), new Array(length - 1)) +export const randomList = curry((length, rng, initPcg): [number, PCGState][] => + scan(([, lastPcg]) => rng(lastPcg), rng(initPcg), new Array(length - 1)) ) export default curry( diff --git a/src/defaults.ts b/src/defaults.ts index 42ab4e0..22ce5c9 100644 --- a/src/defaults.ts +++ b/src/defaults.ts @@ -1,15 +1,15 @@ import Long from 'long' import { StreamScheme, OutputFnType } from './types' -// export const pcgDefaultIncrement8 = 77; -// export const pcgDefaultIncrement16 = 47989; -// export const pcgDefaultIncrement32 = 2891336453; -export const pcgDefaultIncrement64 = Long.fromString('1442695040888963407', true) +// export const pcgDefaultIncrement8 = 77 +// export const pcgDefaultIncrement16 = 47989 +// export const pcgDefaultIncrement32 = Long.fromString('2891336453', 10) +export const pcgDefaultIncrement64 = Long.fromString('1442695040888963407', 10) -// export const pcgDefaultMultiplier8 = 141; -// export const pcgDefaultMultiplier16 = 12829; -// export const pcgDefaultMultiplier32 = 747796405; -export const pcgDefaultMultiplier64 = Long.fromString('6364136223846793005', true) +// export const pcgDefaultMultiplier8 = 141 +// export const pcgDefaultMultiplier16 = 12829 +// export const pcgDefaultMultiplier32 = Long.fromString('747796405') +export const pcgDefaultMultiplier64 = Long.fromString('6364136223846793005', 10) export const pcgDefaultOutputFnType: OutputFnType = OutputFnType.XSH_RR export const pcgDefaultStreamScheme: StreamScheme = StreamScheme.SETSEQ diff --git a/src/index.ts b/src/index.ts index 523a939..57676cb 100644 --- a/src/index.ts +++ b/src/index.ts @@ -13,5 +13,16 @@ export const createPcg32 = createPcg({ outputFns: { [OutputFnType.XSH_RR]: (state: Long): number => ror32(state.shru(59).toInt(), state.shru(18).xor(state).shru(27).toInt()), + [OutputFnType.XSH_RS]: (state: Long): number => state.shru(22).xor(state).shru(state.shru(61).add(22)).toInt(), + [OutputFnType.XSL_RR]: (state: Long): number => ror32(state.shru(59).toInt(), state.shru(32).xor(state).toInt()), + // [OutputFnType.XSL_RR_RR]: (state: Long): number => { + // const high = state.shru(32) + // const newlow = ror32(state.shru(59).toInt(), high.xor(state).toInt()) + // return new Long(ror32(new Long(newlow).and(32).toInt(), high.toInt())).shl(32).or(newlow).toInt() + // }, + [OutputFnType.RXS_M_XS]: (state: Long): number => { + const word = state.shru(13).add(3).xor(state).mul(62169) + return word.shru(11).xor(word).toInt() + }, }, }) diff --git a/src/types.ts b/src/types.ts index 362e09c..6a2f80e 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,13 +1,11 @@ import Long from 'long' -// TODO: Implement more output functions - export enum OutputFnType { XSH_RR = 0, - // XSH_RS = 1 - // XSL_RR = 2 - // XSL_RR_RR = 3 - // RXS_M_XS = 4 + XSH_RS = 1, + XSL_RR = 2, + // XSL_RR_RR = 3 // currently unstable + RXS_M_XS = 4, } export type OutputFn = (state: Long) => number