TL;DR you should only call srand() once and both naive implementations (modulus by max - min + 1 or float division by RAND_MAX) are biased. The best solutions involve calling rand() multiple times: stackoverflow…
Try doing the srand only once (when the app first starts) and just do the rand with you want a new random number
And calling srand each time doesn't hurt, right?
Did you read the link I posted about why calling srand() multiple times is a bad idea? Suppose you use Time.Now.value() (number of…
Travis posted something like this earlier in the thread:
var num=RAND_MIN+(rand()% (RAND_MAX-RAND_MIN));
The lower bounds is RAND_MIN and what's added to that is rand mod the difference between RAND_MAX and RAND_MIN,
you could use
var range= RAND_MAN-RAND_MIN;
to skip a calculation each time, but I wanted it to be clear.
As I explained in my previous comment, Travis' actual post was this:
m + Math.rand() / (RAND_MAX / (n - m + 1) + 1);
where:
m = the desired lower bound
n = the desired upper bound
(Travis' post has a typo where the descriptions of n and m are swapped. It also doesn't explain that RAND_MAX should be converted to a float before doing the division)
RAND_MAX is the maximum number returned by Math.rand() (in the case of Monkey C, 0x7FFFFFFF)
Also as discussed, this solution is better, but not perfect, for the same reason that the modulo solution is imperfect.
using mod makes it simpler
Agreed, but if the question is "why does my random number generator seem to be biased", then the simple mod or float division answers aren't sufficient. (Although the division answer is marginally better than the mod answer)
And that would be calling srand only once or maybe using a better seed, maybe Time.now(),value()?
I already agreed that srand should only be called once, yet also as previously posted, neither the mod nor the float division solutions are truly unbiased, except in the corner case where RAND_MAX is a multiple of the size of the range of numbers you want.
(Note that here as in the C standard, RAND_MAX is the maximum number the the rand function returns, *not* the upper bound of the desired range of random numbers to generate.)
Again I will paste the explanation of why this is the case:
stackoverflow.com/.../11758872
The problem is that you're doing a modulo operation. This would be no problem if
RAND_MAX
would be evenly divisible by your modulus, but usually that is not the case. As a very contrived example, assumeRAND_MAX
to be 11 and your modulus to be 3. You'll get the following possible random numbers and the following resulting remainders:0 1 2 3 4 5 6 7 8 9 10 0 1 2 0 1 2 0 1 2 0 1
As you can see, 0 and 1 are slightly more probable than 2.
Travis posted something like this earlier in the thread:
var num=RAND_MIN+(rand()% (RAND_MAX-RAND_MIN));
The lower bounds is RAND_MIN and what's added to that is rand mod the difference between RAND_MAX and RAND_MIN,
you could use
var range= RAND_MAN-RAND_MIN;
I'd also avoid using RAND_MAX in your example as the name of the argument/variable which represents the upper bound for the range of random numbers you want to generate, since by convention RAND_MAX is supposed to be a constant equal to the largest number that the rand function ever returns (in the C standard and in previous examples in this thread.)
e.g. In Travis's example, RAND_MAX = 0x7FFFFFFF, because Monkey C's Math.rand returns a Number (signed 32-bit integer).
EDIT: Note to mods, I couldn't post this comment and the previous one as a single comment, because the forum kept giving me an error, but somehow posting as separate comments works? Very frustrating.
Jim - just curious why Time.now() is better? Here are the values produced by these functions.
And calling srand each time doesn't hurt, right? If the implementation of rand() is biased, then a new seed prior to each call could actually reduce the bias?
I'm guessing that a different seed might help - that's all. System getTimer restarts at zero each time a device is powered up
And calling srand each time doesn't hurt, right?
Did you read the link I posted about why calling srand() multiple times is a bad idea? Suppose you use Time.Now.value() (number of seconds since the UTC epoch) as your seed and you call your random number code more than once in the same second -- you will get the same "random number" twice. Sure, you can increase the precision by using milliseconds to try to avoid that, but it's still pointless to call srand() every time.
Short answer: calling
srand()
is not like "rolling the dice" for the random number generator. Nor is it like shuffling a deck of cards. If anything, it's more like just cutting a deck of cards.
If the implementation of rand() is biased,
It's not that rand() is biased per se, it's how you use it: the simple modulo or float division to get a number in a certain range is biased.
To be clear, both of these simple solutions are biased:
(The most common solution under discussion - modulo)
min + (Math.rand() % (max - min + 1))
(The alternative that Travis posted - float division)min + Math.rand() / (RAND_MAX.toFloat() / (max - min + 1) + 1);
where:
RAND_MAX
= the largest number that Math.rand() can return (0x7FFFFFFF in Monkey C)
min = the lowest random number you want to generate
max = the highest random number you want to generate
The very simple reason is that in general, you can't distribute RAND_MAX + 1 integers evenly into max - min + 1 buckets.
https://c-faq.com/lib/randrange.html
When N is close to RAND_MAX, and if the range of the random number generator is not a multiple of N (i.e. if (RAND_MAX+1) % N != 0), all of these methods break down: some outputs occur more often than others. (Using floating point does not help; the problem is that rand returns RAND_MAX+1 distinct values, which cannot always be evenly divvied up into N buckets.)
https://stackoverflow.com/a/11758872
The problem is that you're doing a modulo operation. This would be no problem if
RAND_MAX
would be evenly divisible by your modulus, but usually that is not the case. As a very contrived example, assumeRAND_MAX
to be 11 and your modulus to be 3. You'll get the following possible random numbers and the following resulting remainders:0 1 2 3 4 5 6 7 8 9 10 0 1 2 0 1 2 0 1 2 0 1
As you can see, 0 and 1 are slightly more probable than 2.
One option to solve this is rejection sampling: By disallowing the numbers 9 and 10 above you can cause the resulting distribution to be uniform again.
The suggested solution here is to call rand() multiple times, rejecting certain values:
To be fair, the modulo or float division solutions are "good enough" for most people. But again, if the question is "why does my random number code seem to be biased?" the answer is that the simple solutions aren't perfect.