Jump to content
Sign in to follow this  
Tankbuster

round random = unexpected behaviour. round floor = expected behaviour!

Recommended Posts

I'm using random to generate random directions in the northing and then again for the easting, but in testing, got odd results. Perhaps I'm misunderstanding how round works, the biki clearly says it rounds to nearest integer.

x0 = 0;
x1 = 0;
x2 = 0;
xrange = 0;
counter = 0;
while {counter < 1000} do
{
xx=round(random 2);
counter = counter +1;
switch (xx) do
	{
	case 0:	{x0 = x0 +1};
	case 1: {x1 = x1 +1};
	case 2: {x2 = x2 +1};
	case default {xrange = xrange +1};
	};
};
diag_log format ["round x0=%1,x1=%2,x2=%3, default=%4",x0,x1,x2,xrange];

hint format ["round x0=%1,x1=%2,x2=%3, default=%4",x0,x1,x2,xrange];

This picks out 1 twice as often as you'd expect it to.

"round x0=234,x1=530,x2=236, default=0"
"round x0=277,x1=482,x2=241, default=0"
"round x0=254,x1=510,x2=236, default=0"
"round x0=278,x1=488,x2=234, default=0"
"round x0=271,x1=481,x2=248, default=0"

So I changed to using floor. Note that I use random 3 not 2 because floor ALWAYS round down.

x0 = 0;
x1 = 0;
x2 = 0;
xrange = 0;
counter = 0;
while {counter < 1000} do
{
xx=floor(random 3);
counter = counter +1;
switch (xx) do
	{
	case 0:	{x0 = x0 +1};
	case 1: {x1 = x1 +1};
	case 2: {x2 = x2 +1};
	case default {xrange = xrange +1};
	};
};
diag_log format ["floor x0=%1,x1=%2,x2=%3, default=%4",x0,x1,x2,xrange];

hint format ["floor x0=%1,x1=%2,x2=%3, default=%4",x0,x1,x2,xrange];

And sure enough...

"floor x0=320,x1=369,x2=311, default=0"
"floor x0=333,x1=336,x2=331, default=0"
"floor x0=352,x1=329,x2=319, default=0"
"floor x0=330,x1=319,x2=351, default=0"
"floor x0=322,x1=330,x2=348, default=0"
"floor x0=313,x1=347,x2=340, default=0"

That's within what I'd expect to be statistically random.

So, what's happening with round? Or is the question, what's happening with random?

Share this post


Link to post
Share on other sites

Round is statistically random - as long as you use an infinite range of numbers. The problem is when you use a limited range with round. Look at what happens near the ends:

0 = [0.0, 0.5] 0.5 - 0.0 = 0.5 => 0.5 / 2.0 = 25%

1 = [0.5, 1.5] 1.5 - 0.5 = 1.0 => 1.0 / 2.0 = 50%

2 = [1.5, 2.0] 2.0 - 1.5 = 0.5 => 0.5 / 2.0 = 25%

The ends have smaller range when using round.

Share this post


Link to post
Share on other sites

That makes sense now that you put it that way. and it does support what I'm seeing, for sure.

So, using your logic, random floor makes better statistical sense because it better utilizes the numbers at the extreme ends on the range when the range is very small?

Share this post


Link to post
Share on other sites

Yup, you should use floor instead (or some other method that gives a uniform distribution of numbers but: floor random X is pretty much the standard).

Share this post


Link to post
Share on other sites

Just goes to show - never too old to learn something I should have learn 30 years ago! Thanks Muzz.

Share this post


Link to post
Share on other sites

A quick update to this that is relevant and hopefully useful to some others.

I've been using BIS_fnc_selectRandom to do some stuff in a mission script.

Wary of the rounding problem that muzz was good enough to point out to me without making me look a complete knobend, I decided I check out exactly how the distribution of this BIS function worked.

Sure enough, it chooses the first and last element from the array half as often as you'd expect. It can't be trusted to make a true random choice.

I won't bother readers with the code, but here's the results when asked to choose 1 of 8 elements a thousand times. You are seeing the number of times it chose the first element and the second and third etc etc.

"683 1410 1450 1411 1438 1382 1461 765"

So to get around this, I pad the array I'm supplying to the function with a discardable element in the first and last positions, and discard and try again each time it chooses the first or last element, which gives me;

"1150 1092 1106 1116 1031 1090 1112 1132"

Much better. No statistically significant variation there.

Share this post


Link to post
Share on other sites

You got me really interested there.

So, if I get this right, everytime you let the function select something from the array you discard the element selected? Or am I totally wrong here?

Share this post


Link to post
Share on other sites

Not quite. It should only discard (and retry) the result if the function chooses the first or last element. Perhaps I should post the code after all. :)

c0 = 0; c1 = 0; c2 = 0; c3 = 0; c4 = 0; c5 = 0; c6 = 0; c7 = 0;
waituntil {!isnil "bis_fnc_init"};
for "_i" from 0 to 9999 do
{
result = [[9,9],[0,7],[7,7],[7,0],[7,-7],[0,-7],[-7,-7],[-7,0],[-7,7],[9,9]] call BIS_fnc_selectRandom;
result2  = str result;
hint format ["%1", _i];
switch (result2) do
	{
		case "[0,7]":
			{c0 = c0 +1};
		case "[7,7]":
			{c1 = c1 +1};
		case "[7,0]":
			{c2 = c2 +1};
		case "[7,-7]":
			{c3 = c3 +1};
		case "[0,-7]":
			{c4 = c4 +1};
		case "[-7,-7]":
			{c5 = c5 +1};
		case "[-7,0]":
			{c6 = c6 +1};
		case "[-7,7]":
			{c7 = c7 +1};
	};
};
diag_log format ["%1 %2 %3 %4 %5 %6 %7 %8", c0,c1,c2,c3,c4,c5,c6,c7];
hint "complete";

Because the random number generator this function uses round, not floor to make an integer, it has half the chance of choosing the first or last number in it's range than any of the other numbers in it's range. See Muzz's excellent explanation a few posts up.

I wanted to choose a random direction move of 7m in 1 of 8 directions - the cardinal and ordinal directions. Basically N, NE, E, SE,S,SW,W OR NW. You can see those in the array that is passed to the function has those movements. But because of this bug in the function, it didn't choose the first and last direction as often as it should, so I wasn't getting north or north east often enough.

So I added two fake elements ( the 9,9) into the array and didn't count them in the totting up in the switch statement. The remaining totals are statistically random.

This is just test code to prove my findings. To deploy my workaround in the real code, I'd need to loop back into the function if it chooses the first or last element. Something like (untested) this;

result = "[9,9]"; //rig the while check so it works first time in.
while {result = "[9,9]"} do {result = [[9,9],[0,7],[7,7],[7,0],[7,-7],[0,-7],[-7,-7],[-7,0],[-7,7],[9,9]] call BIS_fnc_selectRandom;};

suggestions for better code gratefully received. :)

Edited by Tankbuster

Share this post


Link to post
Share on other sites

Bah. The code I wrote just above doesn't work. Logic is all messed up. Once it chooses a non 9,9, it never goes back in and chooses another one. Might write my own function.

Share this post


Link to post
Share on other sites

So, you are trying to over-complicate something that "floor random" does fine?

Share this post


Link to post
Share on other sites

Well, I thought that using a BIS supplied function might be funky, but it turned out to be junky.

As you say, trying to fix it over complicates matters. I'll write my own function that uses floor random instead of round random.

Share this post


Link to post
Share on other sites

yeah bis fnc random is lame. I'm not a guru, but I did my own neanderthal tests with bis random. I simply did:

_randomShit = [1,2,3,4,5,6,7, etc etc, 70]  BIS_fnc_selectRandom;
hint format ["%1", _randomShit];

On a repeatable radio trigger, It actually would return same numbers alot.

It's garbage. I was gonna use it to create some random objectives me & tryteyker are working on. Don't use it. It sucks.

Share this post


Link to post
Share on other sites

IMO selectRandom is useable, but not with huge arrays. We're choosing numbers from 1-3 and I see no problem in the randomization (although honestly I did not pay that much attention to it, as in, I didn't note down any results. This is just from observing). This is different with huge arrays though, as Iceman described above.

Share this post


Link to post
Share on other sites
IMO selectRandom is useable, but not with huge arrays. We're choosing numbers from 1-3 and I see no problem in the randomization (although honestly I did not pay that much attention to it, as in, I didn't note down any results. This is just from observing). This is different with huge arrays though, as Iceman described above.

It works okay with small amount of selections I guess, but any larger pool, stay away from it. imo

Share this post


Link to post
Share on other sites

We know what the problem is, it's the rounding of the random number it chooses that means it's half as likely to choose the first or last element of the array.

With small array, say three elements - [10,20,30] it's going to be choosing 20 half of the time. The smaller the array is, the worse the effect.

Share this post


Link to post
Share on other sites

I'm not sure why random command or even BIS_fnc_selectRandom should not return the same random results many times over.

If you think about it, it is perfectly normal for something like:

round random 100

To return same results over and over again.

Every time such commands are executed, a random value is selected, why shouldn't it repeat results?

If you intend to filter the results you have to do it manually.

Share this post


Link to post
Share on other sites

Muzzleflash's post in post 2 explains it perfectly.

To achieve an integer, round rounds up or down to the nearest number.

1.6 is below 2 is rounds up to 2.

0.1 is above 0 and rounds down to 0.

But random chooses numbers between 0 and the number you provide it. So it can never choose -0.6 which would round up to 0. It can't choose any negative numbers that would round up 0. So the chance of it choosing a number that will round to 0 is much less than other numbers in it's range.

Likewise for the other end of the range. If you want random 9, it can only choose numbers up to 9. But round 9.4 would also be 9. Again, the numbers it can choose that will round to 9 is greatly reduced.

This is why round random is about half as likely to choose the first or last number in its range.

---------- Post added at 18:16 ---------- Previous post was at 18:10 ----------

IMO selectRandom is useable, ~ We're choosing numbers from 1-3 and I see no problem in the randomization (although honestly I did not pay that much attention to it, as in, I didn't note down any results. This is just from observing). .

You should pay attention to it, mate. When choosing 1 2 or 3, you're getting 2 almost twice as often as 1 or 3.

Share this post


Link to post
Share on other sites

I've tested selectRandom a couple of times now (roughly 10-15 times) and it seems to select the last array fairly often, atleast more often than 2. I'm not starting at 0 though so I ran into problems using floor random 4 since sometimes he gets up to 4 and I don't have a case for that (I'm using 1,2,3). I'll retry starting at 0 though.

//Edit

Okay, I've changed it to start at 0 and used floor random 3 for 0,1,2.

Selection seemed to be even, and looked like this (I only tested up to 10 times though so that may or may not say too much):

0 got select 3 times

1 got selected 3 times

2 got selected 4 times

During selection things seemed to be fairly even aswell, with 1 and 2 going up to 3 before 0 got up to 2 and so on, so one case didn't get too much of an "advantage" over the others so to say, but again, this has only been tested 10 times and thus it doesn't say much about even selection.

Edited by tryteyker

Share this post


Link to post
Share on other sites
I'm not sure why random command or even BIS_fnc_selectRandom should not return the same random results many times over.

If you think about it, it is perfectly normal for something like:

round random 100

To return same results over and over again.

Every time such commands are executed, a random value is selected, why shouldn't it repeat results?

If you intend to filter the results you have to do it manually.

Well, in essence, random is just that. Random. So out of 100 values, why should it be a common thing for it to pick same numbers within only a very short time of testing?

Share this post


Link to post
Share on other sites

Voted, but I have used my own variant (behaves as the suggested) since pretty much forever. Still, should be fixed for those who would use it and accept it with or without looking at it.

Share this post


Link to post
Share on other sites

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now
Sign in to follow this  

×