imneme/pcg-c

HowTo: interject intermittent entropy?

d3x0r opened this issue · 4 comments

d3x0r commented

Not an issue per-se; just a usage query.
My existing RNG is based on grabbing bits from a SHA2 stream. It passes tests very well; but it is computationally expensive. However, as a by-product of doing it this way, when I need another 512 bits of entropy, I call a callback that adds data to the sequence; if nothing additional is added it uses the previous output as the input, if additional data is provided, the previous output plus the additional data is used as the input the SHA2 generator...
https://github.com/d3x0r/-/blob/master/org.d3x0r.common/salty_random_generator.js#L3

Other than the initial seed, I would like to retain that sort of ability... I was planning on using a RNG something like this instead, grabbing 4 or 8 128 bit values at a time... (maybe a configurable length) and then having the ability to modify the seed...

--
Edit: I do plan on using this for procedural generators; (like perlin noise) so reproducability is key; Also for building sectors of voxels using 3d perlin noise to describee like ore content; so I can use the x,y,z of the sector as a seed for the noise generated for that sector...

Ivoz commented

xor bits into the the state bytes?

If your implementation is in complete js and you're wondering about speed, most modern js engines now have very good normal PRNG (xorshift128+) that you might be able to get two instances of and combine, unless the JIT'ed js manages to be just as fast...

d3x0r commented

C and JS run the SHA2 about the same speed... it's just an intense algorithm...
and the standard library functions only allow me one stream of randomness; can't fork it with additional information...

d3x0r commented

https://gist.github.com/d3x0r/345b256be6569c0086c328a8d1b4be01
got some of it roughly ported to JS....
can switch between 16,32,64,128 bit ... uses arrays of half dwords; tried initially with UInt32Array but that was sub-optimal.
32 bit Runs 37 times faster than sha2(also in JS) (10M in 419ms or 23,866/ms)
128 bit runs 16 times faster than sha2(also in JS) (10M in 943ms or 10,604/ms)

sha2 is running (1M in 1594ms or 627/ms) actually that's for only 4 character input hash
something closer to what I uusually use is like (1M in 5688ms or 175/ms (which makes 128bit JS PCG 60 times faster)


C for 100M is pcg_32 using _64 RNG... (no 128bit int)

  • 100M in 1038ms or 96,339/ms (oh that wasn't optimized)
  • 100M in 277ms or 361,011/ms

(a factor of 10 off... surely I can do better than that)


Edit3: Updated Gist above...

(refactored and removed calls, implemented 64_32 mode to match C... )
100M Done in 2242 /ms 44603.692120227457 (32_16)
100M Done in 4924 /ms 20308.692120227457 (64_32) (used to be 4100; give or take... think the math was wrong before too though...)
100M Done in 7263 /ms 13768.415255404103 (128_64) ( used to be 9530)

This is the 'output' code... for 32_16; before adding this, it did 100M in 723ms (138k/ms), after it takes 3x longer.

This is a painful thing to do I guess...

				//return pcg_rotr_16(((state >> 10u) ^ state) >> 12u, state >> 28u);
				out[0] = state[0] ^( ( ( state[0] >> 10 ) | state[1] << 6 ) & 0xFFFF);
				out[1] = state[1] ^( ( state[1] >> 10 ) & 0xFFFF);

				// >> 12 is  0 index and 12
				out[0] = ( out[0] >> 12 | out[1] << 4 ) & 0xFFFF
				out[1] = ( out[1] >> 12 ) & 0xFFFF

				//pcg_rotr_64( out, state[3]>>28 );
				const rot = state[1]>>12;
				out[0] = out[0] >> rot | ( ( out[1] << (16-rot) ) & ( 0xFFFF << (16-rot) ) );
				out[1] = out[1] >> rot | ( ( out[0] << (16-rot) ) & ( 0xFFFF << (16-rot) ) );
				return out[0];
d3x0r commented

Ya, this is bad for generating a stream of bits... not really sure but 70% of the time the value is 0; and it's not a bounded return; basically I'm returning the low 2 shorts concated... in 10M bits from sha2 it's within +/- 8200 or like 0.082% deviation; and turns out all the other process is heavier than I though.