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:
parent
54ddcd0f5a
commit
b5d8806eb1
6 changed files with 3477 additions and 3456 deletions
|
@ -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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue