Random Numbers with Seed; Large Integers?

Is there a large integer type?

I’m trying to write a decent pseudo random number generator so that I can generate fractal detail (e.g. positions of stars and asteroids) in a repeatable fashion.

Failing that, has someone got a decent working PNRG written? (I found a JavaScript implementation of the Mesenne Twister, which would be fine except that it uses JavaScript features that are missing from UnityScript).

This doesn’t really qualify as a “good” PRNG, but it works surprisingly well considering how very simple it is:

var randomSeed : float = 1;

function PseudoRandom() {
	randomSeed = (randomSeed*9301 + 49297) % 233280;
	return randomSeed / 233280;
}

That returns a float between 0 and 1; you can generate integers with it in the usual way. You can see it in action here. The “randomness” seems acceptable for typical game use as long as you call it at least once before you use it “for real”, since the first result is highly ordered.

–Eric

Nice – thank you, I think that will serve my purpose.

Turns out the problem with the Mersenne code is that it makes extensive use of bitwise XOR (^) which is (apparently … strangely) not implemented in UnityScript (and writing ( A | B ) (~ ( A B ) ) for A ^ B throughout will get old fast.

e.g.

function genrand_int32()

{

	//c//unsigned long y;

	//c//static unsigned long mag01[2]={0x0UL, MATRIX_A};

	var y;

	var mag01 = new Array(0x0, MATRIX_A);

	/* mag01[x] = x * MATRIX_A  for x=0,1 */



	if (mti >= N) { /* generate N words at one time */

		//c//int kk;

		var kk;



		if (mti == N+1)   /* if init_genrand() has not been called, */

			init_genrand(5489); /* a default initial seed is used */



		for (kk=0;kk<N-M;kk++) {

			//c//y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK);

			//c//mt[kk] = mt[kk+M] ^ (y >> 1) ^ mag01[y  0x1];

			y = unsigned32((mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK));

			mt[kk] = unsigned32(mt[kk+M] ^ (y >>> 1) ^ mag01[y  0x1]);

		}

		for (;kk<N-1;kk++) {

			//c//y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK);

			//c//mt[kk] = mt[kk+(M-N)] ^ (y >> 1) ^ mag01[y  0x1];

			y = unsigned32((mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK));

			mt[kk] = unsigned32(mt[kk+(M-N)] ^ (y >>> 1) ^ mag01[y  0x1]);

		}

		//c//y = (mt[N-1]&UPPER_MASK)|(mt[0]&LOWER_MASK);

		//c//mt[N-1] = mt[M-1] ^ (y >> 1) ^ mag01[y  0x1];

		y = unsigned32((mt[N-1]&UPPER_MASK)|(mt[0]&LOWER_MASK));

		mt[N-1] = unsigned32(mt[M-1] ^ (y >>> 1) ^ mag01[y  0x1]);

		mti = 0;

	}



	y = mt[mti++];



	/* Tempering */

	//c//y ^= (y >> 11);

	//c//y ^= (y << 7)  0x9d2c5680;

	//c//y ^= (y << 15)  0xefc60000;

	//c//y ^= (y >> 18);

	y = unsigned32(y ^ (y >>> 11));

	y = unsigned32(y ^ ((y << 7)  0x9d2c5680));

	y = unsigned32(y ^ ((y << 15)  0xefc60000));

	y = unsigned32(y ^ (y >>> 18));



	return y;

}

Here’s your PRNG in action generating an asteroid field – position, size, etc. are determined via the PNRG so that if you leave a star system and then return, everything will be the same (except for their orbital position, which is linked to the actual time).

41415--1536--$picture_1_601.png

That’s pretty cool! I can’t claim credit for that routine; I found it on an ancient website a while ago while looking for pseudo-random generators, was skeptical given how trivial it is, but gave it a try anyway and got reasonable results with it. Plus it’s really fast. :wink:

–Eric

It’s very sweet. I’ve got it generating starfields and asteroid belts and there’s no ugly frequency patterns that I can see.

FYI, I wrote a little testbed to analyze the PNRG to make sure it wouldn’t do anything pathological (you don’t want it to start cycling and produce 5 copies of every star or whatever). Here’s some of the output (100,000 trials):

Results

Seed: 2
0.0 – 0.1: 9.981%
0.1 – 0.2: 9.99%
0.2 – 0.3: 10.052%
0.3 – 0.4: 9.979000000000001%
0.4 – 0.5: 9.962%
0.5 – 0.6: 10.029%
0.6 – 0.7: 10.027000000000001%
0.7 – 0.8: 9.965%
0.8 – 0.9: 10.019%
0.9 – 0.10: 9.996%

Repeats: 0
Ave Difference*: 0.3334565243055594

  • Average difference between consecutive values.

I get very similar results for every seed I’ve tried, including 0. (And yes, my code builds an array containing every single result and checks to see if it is recreated.)

So it looks very safe to use for “fractal” content generation.

<html>
	<head>
	</head>
	<body>
		<script type="text/javascript">
			var seed = 1.0;
			
			function Evaluate(){
				var d = document.getElementById("output");
				var results = new Array();
				var resultBins = new Array();
				var sumDifferences = 0.0;
				for( var i = 0; i < 10; i++ ){
					resultBins[i] = 0;
				}
				var r = 0;
				var previous = 0;
				var repeats = 0;
				var seed = parseFloat(document.testForm.inputValue.value);
				var output = "[b]Seed[/b]: " + seed + "
";
				for( var i = 0; i < 100000; i++ ){
					r = PseudoRandom();
					resultBins[Math.floor(r * 10)]++;
					sumDifferences += Math.abs(r - previous);
					previous = r;
					r = r.toString();
					if(results[r]){
						repeats++;
					}
				}
				for( var i = 0; i < 10; i++){
					output += "0." + i + " -- 0." + (i+1) + ": " + 0.001 * resultBins[i] + "%
";
				}
				output += "
[b]Repeats[/b]: " + repeats;
				output += "
[b]Ave Difference[/b]: " + (sumDifferences * 0.00001);
				d.innerHTML = "<h3>Results</h3>

" + output + "</p>";
				return false;
			}
			
			function PseudoRandom() {
				seed = (seed*9301 + 49297) % 233280;
				return seed / 233280;
			} 
		</script>
		<form name="testForm" onsubmit="return Evaluate();">
		<input name="inputValue" type="text" value="1.0">
		<input type="submit" value="Enter">
		</form>
		<div id="output">
		</div>
	</body>
</html>

Aside: it’s scary how fast this runs in a browser with today’s computer hardware.[/code]

Excellent! I had the vague thought of doing some stats just out of curiosity, but never got farther than “hmm, the stuff on screen looks OK to me…”

–Eric

i must be feeling a bit thick today. but can you post a little snippet of unity code showing this producing a random field of prefabs please? I think I’m missing something fundamental in its usage… :wink:

cheers.

For another project I altered it to return a range of integers, but in this form it’s just like Random.value.

var randomSeed : float = 1; 
var somePrefab : GameObject;

function Start() {
   for (i = 0; i < 20; i++) {
      somePlace = Vector3(PseudoRandom()*50, 0, PseudoRandom()*50);
      Instantiate(somePrefab, somePlace, Quaternion.identity);
   }
}

function PseudoRandom() { 
   randomSeed = (randomSeed*9301 + 49297) % 233280; 
   return randomSeed / 233280; 
}

So you get the same “random” distribution of prefabs every time unless you change the seed number.

–Eric

the fog clears! thanks man.

Cheers.