More True Randomess - RNGCryptoServiceProvider explanation required

Hay there, it’s been a while but now I have a new Question!!! :smiley:

I wrote some code that needed randomness and then checked the results “UnityEngine.Random()” was returning .

I didn’t liked the way it presented a pattern in values that were supposed to be " random".
I was aware that sort of randomness wasn’t the so called true randomness but still I thought it could achieve better results.

I ended up using the RNGCryptoServiceProvider class from Microsoft for a " higher" quality of randomness.

This is the code I used, I basically copy-pasted the logic they explain in their reference page:

	int RandomWithRNGcryptography(int range){

		//Set up RNG for more randomness
		RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();

		//Convert range from int to byte
		byte bRange = (byte) range;

		byte[] arr = new byte[1];
		do{

			rng.GetBytes(arr);
		}
		while(!IsFairRandom(arr[0],bRange));

		return (int)((arr[0] % bRange) +1);
	}

	bool IsFairRandom(byte number,byte range){

		range = range>0?range:(byte)1;
		int fullSetOfValues = Byte.MaxValue /range;
		return number < range * fullSetOfValues;
	}

MY QUESTION IS… CAN YOU GUYS EXPLAIN THAT STUFF TO ME? O.O

I’ve checked the numbers this returns and all is doing well, now I would like to know why everything is working because I haven’t done much more than copy-pasting logic I don’t understand :confused:

Also, I had to set up a conditional assignment in the bool because sometimes it divided by zero… I don’t understand though!

Extra Mile: why Unity only uses UnityEngine.Random(), that approximates sometimes too much for something supposedly random?

Please help me learning and thanks a bunch!!!

I think you’re on the complete wrong track here. First of all there is no true randomness in a computer without special hardware (Something like that). Unity’s PRNG (Pseudorandom number generator) is actually a pretty good one (See this post).

Keep in mind that the point of “RNGCryptoServiceProvider” is not to be “more random” but to be cryptographically secure. Also those random generators can be significantly slower than Unity’s. For what kind of application do you need the random numbers and which range do you actually need? What patterns do you actually see?

The code on the MSDN example page is actually well commented. You just copied the code without the comments… The example is actually a bad example as it’s just a very specific application and is more directed towards gambling. The example code uses just single byte values so the largest number would be 255. In most cases might need larger ranges. The “RNGCryptoServiceProvider” is a bit of a pain to work with as you would need to get more than one byte and construct larger numbers yourself.

Your range clamping also just seems strange. It won’t divide by “0” unless you pass 0 as range (or any other value that when casted to byte will be null, like 256 for example). That’s why the original code had a check in there that throws an exception when the range is 0 or smaller. You did remove that check.

I’m not quite sure what you actually want from us. Explaining some sample code from Microsoft which most likely isn’t related to your actual problem doesn’t make much sense. You should focus on your actual problem.

Anyways, the point of “IsFairRandom” is to ignore values that are in a range that doesn’t allow every number to appear equally likely.

As an example imagine you had a number generator that can generate evenly distributed numbers between 0 and 15 and you want a range of “6” (values between 0 and 5) just like in the example. By taking the modulo at the end we simply wrap-around after our defined range:

 0 --> 0 ------
 1 --> 1
 2 --> 2
 3 --> 3    Set 1
 4 --> 4
 5 --> 5
 6 --> 0 ------
 7 --> 1
 8 --> 2
 9 --> 3    Set 2
10 --> 4
11 --> 5
12 --> 0 ------
13 --> 1
14 --> 2    Set 3 (incomplete)
15 --> 3
       4 (missing)
       5 (missing)

As you can see because our initial range was 0 to 15 the values 4 and 5 are less likely than the numbers 0 to 3 because “16” can’t be divided by “6” without remainder. IsFairRandom simply checks if the rolled number is in the range of a “full set”. The first set is 0 - 5 the second set is 6-11. The last set is not full because 4 and 5 are missing. So IsFairRandom simply returns false when the number is greater than 11 so it simply ignores the last incomplete set and rolls a new number until it is in range.

Of course in the actual example code the initial range was “256” (0 - 255) since the incoming value is a byte.