Published
Edited
Nov 5, 2020
Fork of xorshift
1 star
Insert cell
Insert cell
xorShiftF64 = {
// Try this out in the console:

// const u = new Uint32Array(4);
// const f = new Float64Array(u.buffer);
// f[0] = 1;
// f[1] = 2;
// return { u, f };
//
// --> Object {
// u: Uint32Array(2) [0, 1072693248, 0, 1073741824]
// f: Float32Array(2) [1, 2]
// }
// convert that and we get the following two binary bit strings:

// 0b00111111_11110000_00000000_00000000_00000000_00000000_00000000_00000000
// 0b01000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000

// In other words: in the range [1.0, 2.0) of Float64
// we can use xorshift on the lower 52 bits to get
// a uniform random distribution. Subtract one and we
// get an fast approximation of uniform random in range (0, 1.0)
// We use typed arrays to "cast" between Uint32 and Float64
const u = new Uint32Array(2);
const f = new Float64Array(u.buffer);
// since JS bitshifting only works on 32 bits we
// divide our "64 bit uint" into two chunks
// and manually ensure that bits shifted out of the
// bottom of the high chunk, or the top of the
// low chunk ends up in the other chunk
let x_l = (Math.random() * 0x100000000) | 0;
let x_h = (Math.random() * 0x100000) | 0;
return function xorShiftF32() {
// closures never inline captured variables,
// hence these local variables to fix that
// x ^= x << 13
let h = (x_h << 13) + (x_l >>> 19);
let l = x_l << 13;

// x ^= x >> 17
l ^= (l >> 17) + (h << 15);
h ^= h >>> 17;

// x ^= x << 5;
x_h = h ^= (h << 5) + (l >>> 27);
u[0] = x_l = l ^= l << 5;
u[1] = 0b111111111100000000000000000000 | (h & 0xFFFFF);
return f[0] - 1;
};
}
Insert cell
Array.from({ length: 1000 }, xorShiftF64)
Insert cell
// Since we're probably want to have lots of random values in typed arrays,
// we might as well operate directly on said arrays
xorShiftF64Array = {
let x_l = (Math.random() * 0x100000000) | 0;
let x_h = (Math.random() * 0x100000) | 0;
return function xorShiftF64Array(f) {
const u = new Uint32Array(f.buffer);
for (let i = 0, j = 0; i < f.length; i++) {
// x ^= x << 13
let h = (x_h << 13) + (x_l >>> 19);
let l = x_l << 13;

// x ^= x >> 17
l ^= (l >> 17) + (h << 15);
h ^= h >>> 17;

// x ^= x << 5;
x_h = h ^= (h << 5) + (l >>> 27);
u[j++] = x_l = l ^= l << 5;
u[j++] = 0b111111111100000000000000000000 | (h & 0xFFFFF);
f[i] -= 1;
}
return f;
};
}
Insert cell
xorShiftF64Array(new Float64Array(1000))
Insert cell
{
const n = 1e7;
const A = new Array(n).fill(0);
let time = +new Date();
for (let i = 0; i < n; i++) A[i] = Math.random();
time = (+new Date() - time) / 1000;

return md`${(n / 1e6 / time).toFixed(
1
)} million pseudorandom numbers per second (individual calls to \`Math.random\`)`;
}
Insert cell
{
const n = 1e7;
const A = new Array(n).fill(0);

let time = +new Date();
for (let i = 0; i < n; i++) A[i] = xorShiftF64();
time = (+new Date() - time) / 1000;

return md` ${(n / 1e6 / time).toFixed(
1
)} million pseudorandom numbers per second (individual calls to \`xorShiftF64\`)`;
}
Insert cell
{
const n = 1e7;
const A = new Float64Array(n);
let time = +new Date();
for (let i = 0; i < n; i++) A[i] = Math.random();
time = (+new Date() - time) / 1000;

return md`${(n / 1e6 / time).toFixed(
1
)} million pseudorandom numbers per second (fill \`Float64Array\` with individual calls to \`Math.random\`)`;
}
Insert cell
{
const n = 1e7;
const A = new Float64Array(n);

let time = +new Date();
xorShiftF64Array(A);
time = (+new Date() - time) / 1000;

return md` ${(n / 1e6 / time).toFixed(
1
)} million pseudorandom numbers per second (apply \`xorShiftF64Array\` to \`Float64Array\`)`;
}
Insert cell
{
const height = 500,
context = DOM.context2d(width, height);

const randomVals = new Float64Array(width * 2);
do {
context.fillStyle = "rgba(255,255,255,0.01)";
context.fillRect(0, 0, width, height);
context.fillStyle = "#000";
xorShiftF64Array(randomVals);
for (let i = 0; i < width; i++)
context.fillRect(
width * randomVals[i * 2],
height * randomVals[i * 2 + 1],
1,
1
);
yield context.canvas;
} while (true);
}
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more