1 | /**
|
2 | * @module prng
|
3 | */
|
4 |
|
5 | import { Xorshift32 } from './Xorshift32.js'
|
6 | import * 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 | */
|
21 | export 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 |
|
77 | uint64_t s[2];
|
78 |
|
79 | static inline uint64_t rotl(const uint64_t x, int k) {
|
80 | return (x << k) | (x >> (64 - k));
|
81 | }
|
82 |
|
83 | uint64_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 |
|
92 | int 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 | */
|