Last active
April 3, 2018 22:26
-
-
Save d3x0r/345b256be6569c0086c328a8d1b4be01 to your computer and use it in GitHub Desktop.
Javascript port of PCG RNG
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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