UNPKG

3.41 kBJavaScriptView Raw
1/**
2 * @module prng
3 */
4
5import { Xorshift32 } from './Xorshift32.js'
6import * as binary from '../binary.js'
7
8/**
9 * This is a variant of xoroshiro128plus - the fastest full-period generator passing BigCrush without systematic failures.
10 *
11 * This implementation follows the idea of the original xoroshiro128plus implementation,
12 * but is optimized for the JavaScript runtime. I.e.
13 * * The operations are performed on 32bit integers (the original implementation works with 64bit values).
14 * * The initial 128bit state is computed based on a 32bit seed and Xorshift32.
15 * * This implementation returns two 32bit values based on the 64bit value that is computed by xoroshiro128plus.
16 * Caution: The last addition step works slightly different than in the original implementation - the add carry of the
17 * first 32bit addition is not carried over to the last 32bit.
18 *
19 * [Reference implementation](http://vigna.di.unimi.it/xorshift/xoroshiro128plus.c)
20 */
21export class Xoroshiro128plus {
22 /**
23 * @param {number} seed Unsigned 32 bit number
24 */
25 constructor (seed) {
26 this.seed = seed
27 // This is a variant of Xoroshiro128plus to fill the initial state
28 const xorshift32 = new Xorshift32(seed)
29 this.state = new Uint32Array(4)
30 for (let i = 0; i < 4; i++) {
31 this.state[i] = xorshift32.next() * binary.BITS32
32 }
33 this._fresh = true
34 }
35
36 /**
37 * @return {number} Float/Double in [0,1)
38 */
39 next () {
40 const state = this.state
41 if (this._fresh) {
42 this._fresh = false
43 return ((state[0] + state[2]) >>> 0) / (binary.BITS32 + 1)
44 } else {
45 this._fresh = true
46 const s0 = state[0]
47 const s1 = state[1]
48 const s2 = state[2] ^ s0
49 const s3 = state[3] ^ s1
50 // function js_rotl (x, k) {
51 // k = k - 32
52 // const x1 = x[0]
53 // const x2 = x[1]
54 // x[0] = x2 << k | x1 >>> (32 - k)
55 // x[1] = x1 << k | x2 >>> (32 - k)
56 // }
57 // rotl(s0, 55) // k = 23 = 55 - 32; j = 9 = 32 - 23
58 state[0] = (s1 << 23 | s0 >>> 9) ^ s2 ^ (s2 << 14 | s3 >>> 18)
59 state[1] = (s0 << 23 | s1 >>> 9) ^ s3 ^ (s3 << 14)
60 // rol(s1, 36) // k = 4 = 36 - 32; j = 23 = 32 - 9
61 state[2] = s3 << 4 | s2 >>> 28
62 state[3] = s2 << 4 | s3 >>> 28
63 return (((state[1] + state[3]) >>> 0) / (binary.BITS32 + 1))
64 }
65 }
66}
67
68/*
69// Reference implementation
70// Source: http://vigna.di.unimi.it/xorshift/xoroshiro128plus.c
71// By David Blackman and Sebastiano Vigna
72// Who published the reference implementation under Public Domain (CC0)
73
74#include <stdint.h>
75#include <stdio.h>
76
77uint64_t s[2];
78
79static inline uint64_t rotl(const uint64_t x, int k) {
80 return (x << k) | (x >> (64 - k));
81}
82
83uint64_t next(void) {
84 const uint64_t s0 = s[0];
85 uint64_t s1 = s[1];
86 s1 ^= s0;
87 s[0] = rotl(s0, 55) ^ s1 ^ (s1 << 14); // a, b
88 s[1] = rotl(s1, 36); // c
89 return (s[0] + s[1]) & 0xFFFFFFFF;
90}
91
92int main(void)
93{
94 int i;
95 s[0] = 1111 | (1337ul << 32);
96 s[1] = 1234 | (9999ul << 32);
97
98 printf("1000 outputs of genrand_int31()\n");
99 for (i=0; i<100; i++) {
100 printf("%10lu ", i);
101 printf("%10lu ", next());
102 printf("- %10lu ", s[0] >> 32);
103 printf("%10lu ", (s[0] << 32) >> 32);
104 printf("%10lu ", s[1] >> 32);
105 printf("%10lu ", (s[1] << 32) >> 32);
106 printf("\n");
107 // if (i%5==4) printf("\n");
108 }
109 return 0;
110}
111*/