Skip to content

Instantly share code, notes, and snippets.

@d3x0r
Last active April 3, 2018 22:26
Show Gist options
  • Save d3x0r/345b256be6569c0086c328a8d1b4be01 to your computer and use it in GitHub Desktop.
Save d3x0r/345b256be6569c0086c328a8d1b4be01 to your computer and use it in GitHub Desktop.
Javascript port of PCG RNG
// ported from https://github.com/imneme/pcg-c
// http://www.pcg-random.org/using-pcg.html
const _UINTS = 4;
// records
// : 2 : Done in 1321 /ms 75700.2271006813 151400.4542013626
// : 4 : Done in 3538 /ms 28264.55624646693 113058.22498586772(kbpms)
// : 8 : Done in 5671 /ms 17633.574325515783 141068.59460412627
//
function getState() {
return {
state: [0,0,0,0,0,0,0,0],
inc: [0,0,0,0,0,0,0,0],
out: [0,0,0,0,0,0,0,0],
get : null // will be the step and output function pair
}
}
const PCG_MULTIPLIER = _UINTS==8?( [ 0xF645, 0x9FCC, 0xDF64, 0x4385, 0x5DA4, 0x1FC6, 0xED05, 0x2360 ] )
: _UINTS==4?( [ 0x7F2D, 0x4C95, 0xF42D, 0x5851 ] )
: _UINTS==2?( [ 0x77B5, 0x2C92 ] )
: _UINTS==1?( [0x321D] )
: console.log( "Unsupported DWORD count:", _UINTS );
const PCG_DEFAULT_INCREMENT = _UINTS==8?( [ 0x814F,0xF767,0x7B7E ,0x1405, 0x7F2D, 0x4C95, 0xF42D, 0x5851 ] )
: _UINTS==4?( [ 0x7F2D, 0x4C95, 0xF42D, 0x5851 ] )
: _UINTS==2?( [ 0x4B05, 0xAC56 ] )
: _UINTS==1?( [0xBB75] )
: console.log( "Unsupported DWORD count:", _UINTS );
function pcg_setseq_128_srandom_r( initstate, initseq )
{
const rng = getState();
//rng->inc = (initseq << 1u) | 1u;
if( initseq ) {
if( typeof( initseq ) === "number" ) {
rng.inc[ 0 ] = (initseq & 0x7FFF) << 1 | 1;
rng.inc[ 1 ] = (initseq & 0x7FFF8000) >> 15;
} else {
// should validate it is a uint32 array or is an array at least...
rng.inc = initseq;
}
} else {
rng.inc = PCG_DEFAULT_INCREMENT;
}
// step one time (from 0 to increment)
pcg_setseq_64_xsh_rr_32_r(rng);
//pcg_setseq_step_r(rng);
if( initstate ) {
function add( a, b ) {
var over = 0;
//console.log( "MullAdd:", a, b, c );
for( var i = 0; i < _UINTS; i++ ) {
over += ( a[i] + b[i] );
a[i] = over & 0xFFFF; over >>>= 16;
}
}
add( rng.state, initstate );
}
pcg_setseq_64_xsh_rr_32_r(rng);
//pcg_setseq_step_r(rng);
rng.get = pcg_setseq_64_xsh_rr_32_r;
return rng;
function pcg_setseq_64_xsh_rr_32_r( )
{
const out = rng.out;
const state = rng.state;
const a = rng.state;
const b = PCG_MULTIPLIER;
const c = rng.inc;
var over = 0;
if( _UINTS === 1 )
a[0] = ( (a[0]*b[0])+c[0] ) & 0xFFFF;
else if( _UINTS === 2 ) {
over = ( (a[0]*b[0])+c[0] );
const s0 = a[0] = over & 0xFFFF; over >>>= 16;
over += ( (a[1]*b[1])+c[1] );
const s1 = a[1] = over & 0xFFFF; over >>>= 16;
//return pcg_rotr_16(((state >> 10u) ^ state) >> 12u, state >> 28u);
const a0 = s0 ^( ( ( s0 >> 10 ) | s1 << 6 ) & 0xFFFF);
const a1 = s1 ^( ( s1 >> 10 ) & 0xFFFF);
// >> 12 is 0 index and 12
const b0 = ( a0 >> 12 | a1 << 4 ) & 0xFFFF
const b1 = ( a1 >> 12 ) & 0xFFFF
//pcg_rotr_64( out, state[3]>>28 );
const rot = s1>>12;
const c0 = b0 >> rot | ( ( b1 << (16-rot) ) & ( 0xFFFF << (16-rot) ) );
const c1 = b1 >> rot | ( ( b0 << (16-rot) ) & ( 0xFFFF << (16-rot) ) );
return c0;
}
else if( _UINTS === 4 ) {
over = ( (a[0]*b[0])+c[0] );
a[0] = over & 0xFFFF; over >>>= 16;
over += ( (a[1]*b[1])+c[1] );
const s1 = a[1] = over & 0xFFFF; over >>>= 16;
over += ( (a[2]*b[2])+c[2] );
const s2 = a[2] = over & 0xFFFF; over >>>= 16;
over += ( (a[3]*b[3])+c[3] );
const s3 = a[3] = over & 0xFFFF; over >>>= 16;
//return pcg_rotr_32(((state >> 18u) ^ state) >> 27u, state >> 59u);
// >> 18 is >> 16 (1 index) and 2....
//const a0 = s0 ^(( ( s1 >> 2 ) | s2 << 14 ) & 0xFFFF);
const a1 = s1 ^(( ( s2 >> 2 ) | s3 << 14 ) & 0xFFFF);
const a2 = s2 ^(( ( s3 >> 2 ) ) & 0xFFFF);
const a3 = s3;
// >> 27 is 1 index and 11
const b0 = ( a1 >> 11 | a2 << 5 ) & 0xFFFF
const b1 = ( a2 >> 11 | a3 << 5 ) & 0xFFFF
//const b2 = ( a3 >> 11 ) & 0x001f
//pcg_rotr_64( out, state[3]>>11 );
const rot = s3>>11;
const h1 = b0 >> rot | ( ( b1 << (16-rot) ) & ( 0xFFFF << (16-rot) ) );
const h2 = b1 >> rot | ( ( b0 << (16-rot) ) & ( 0xFFFF << (16-rot) ) );
// result with a 32 bit value.
return h1 | (h2 << 16);
}
else if( _UINTS === 8 ) {
over = ( (a[0]*b[0])+c[0] );
a[0] = over & 0xFFFF; over >>>= 16;
over += ( (a[1]*b[1])+c[1] );
a[1] = over & 0xFFFF; over >>>= 16;
over += ( (a[2]*b[2])+c[2] );
a[2] = over & 0xFFFF; over >>>= 16;
over += ( (a[3]*b[3])+c[3] );
const s3 = a[3] = over & 0xFFFF; over >>>= 16;
over += ( (a[4]*b[4])+c[4] );
const s4 = a[4] = over & 0xFFFF; over >>>= 16;
over += ( (a[5]*b[5])+c[5] );
const s5 = a[5] = over & 0xFFFF; over >>>= 16;
over += ( (a[6]*b[6])+c[6] );
const s6 = a[6] = over & 0xFFFF; over >>>= 16;
over += ( (a[7]*b[7])+c[7] );
const s7 = a[7] = over & 0xFFFF; over >>>= 16;
//return pcg_rotr_64(((state >> 29u) ^ state) >> 58u, state[7] >> 12 );
// >> 29 is >> 16 (1 index) and 13....
//const a0 = s0 ^(( ( s1 >> 13 ) | s2 << 3 ) & 0xFFFF);
//const a1 = s1 ^(( ( s2 >> 13 ) | s3 << 3 ) & 0xFFFF);
//const a2 = s2 ^(( ( s3 >> 13 ) | s4 << 3 ) & 0xFFFF);
const a3 = s3 ^(( ( s4 >> 13 ) | s5 << 3 ) & 0xFFFF);
const a4 = s4 ^(( ( s5 >> 13 ) | s6 << 3 ) & 0xFFFF);
const a5 = s5 ^(( ( s6 >> 13 ) | s7 << 3 ) & 0xFFFF);
const a6 = s6;
const a7 = s7;
// >> 58 is 3 words (3 * 16 - 48) and 10
// and +4 << 6
const b0 = ( a3 >> 10 | a4 << 6 ) & 0xFFFF
const b1 = ( a4 >> 10 | a5 << 6 ) & 0xFFFF
const b2 = ( a5 >> 10 | a6 << 6 ) & 0xFFFF
const b3 = ( a6 >> 10 | a7 << 6 ) & 0xFFFF
//const b4 = ( a7 >> 10 ) & 0x3F
//pcg_rotr_64( out, state[7]>>12 );
const rot = s7>>12;
const c0 = b0 >> rot | ( ( b1 << (16-rot) ) & ( 0xFFFF << (16-rot) ) );
const c1 = b1 >> rot | ( ( b2 << (16-rot) ) & ( 0xFFFF << (16-rot) ) );
const c2 = b2 >> rot | ( ( b3 << (16-rot) ) & ( 0xFFFF << (16-rot) ) );
const c3 = b3 >> rot | ( ( b0 << (16-rot) ) & ( 0xFFFF << (16-rot) ) );
// result with a 32 bit value.
//return out[0] | (out[1] << 16) + out[2] * 65535.0 + ( ( out[3] & 0xFF ) * 0x1000000 ) ;
return c0 | (c1 << 16);// + out[2] * 65535.0 + ( ( out[3] & 0xFF ) * 0x1000000 ) ;
}
else {
console.log( "Faking it, not a binary power?" );
function multadd( a, b, c ) {
var over = 0;
//console.log( "MullAdd:", a, b, c );
for( var i = 0; i < _UINTS; i++ ) {
over += ( a[i] * b[i] ) + c[i];
a[i] = over & 0xFFFF; over >>>= 16;
}
}
//rng->state = rng->state * PCG_DEFAULT_MULTIPLIER_64 + rng->inc;
multadd( rng.state, PCG_MULTIPLIER, rng.inc );
}
}
}
var n, m;
var testRng = pcg_setseq_128_srandom_r( [0x1556,0x2143,0x5533,0x6644,0x5554,0x5523,0x5554,0x5554], 0/*67177172*/ )
// debug logging, dumps full states before and after generating a number....
console.log( testRng, "\n", testRng.get(testRng), "\n",testRng );
console.log( testRng, "\n", testRng.get(testRng), "\n",testRng );
console.log( testRng, "\n", testRng.get(testRng), "\n",testRng );
var start = Date.now();
for( n = 0; n < 10000; n++ )
for( m = 0; m < 10000; m++ ) {
testRng.get(testRng);
//console.log( testRng );
}
console.log( "Done in ", Date.now() - start, "/ms", (m*n)/(Date.now()-start), ((m*n)/(Date.now()-start)) * _UINTS );
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment