Fix tiny error in distribution of die rolls

"random() % n" is sound only when n is a power of two.  The error is
hardly relevant in Empire, because random() yields 31 bits, and our n
are always much smaller than 2^31.  Fix it anyway.

Use smallest the 2^m >= n instead of n, and discard numbers exceeding
n.

Bonus: faster for me even in the worst case n = 2^m+1.

Like the recent change to damage(), this changes some of the server's
die rolls, only this time the effect is pretty pervasive.  Worse,
fairland now creates a completely different random map for the same
seed.  Update expected smoke test results accordingly.
This commit is contained in:
Markus Armbruster 2012-08-19 12:19:04 +02:00
parent 54ddcd0f5a
commit b5d8806eb1
6 changed files with 3477 additions and 3456 deletions

View file

@ -54,22 +54,43 @@ pct_chance(int pct)
return roll(100) <= pct;
}
static unsigned
round_up_to_pow2(unsigned val)
{
val--;
val |= val >> 1;
val |= val >> 2;
val |= val >> 4;
val |= val >> 8;
val |= val >> 16;
val++;
return val;
}
/*
* Return a random number in [0..N-1].
* N must be in [1..2^31-1].
*/
int
roll0(int n)
{
return random() % n;
unsigned pow2 = round_up_to_pow2(n);
int r;
do
r = random() & (pow2 - 1);
while (r >= n);
return r;
}
/*
* Return a random number in [1..N].
* N must be in [0..2^31-1].
*/
int
roll(int n)
{
return 1 + random() % n;
return 1 + roll0(n);
}
/*