Fix IRandomBetween returning out-of-range numbers (#173)

This commit is contained in:
Anonymous Maarten 2022-09-22 22:39:52 +02:00 committed by GitHub
parent f1849412e9
commit b7da8770b4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 37 additions and 5 deletions

View File

@ -195,8 +195,14 @@ int IRandomBetween(int pA, int pB) {
int num;
char s[32];
num = (pB + 1 - pA) * (rand() / (double)RAND_MAX) + pA;
return num;
num = rand();
#if RAND_MAX == 0x7fff
// If RAND_MAX == 0x7fff, then `num` can be seen as a fixed point number with 15 fractional and 17 integral bits
return pA + ((num * (pB + 1 - pA)) >> 15);
#else
// If RAND_MAX != 0x7fff, then use floating numbers (alternative is using modulo)
return pA + (int)((pB + 1 - pA) * (num / ((float)RAND_MAX + 1)));
#endif
}
// IDA: int __usercall PercentageChance@<EAX>(int pC@<EAX>)

View File

@ -96,10 +96,36 @@ void test_utility_PathCat() {
}
void test_utility_IRandomBetween() {
tU32 source_y_delta;
int r;
int i;
int j;
int actual_min;
int actual_max;
struct {
int min;
int max;
} ranges[] = {
{ -2, 1 },
{ 1, -2 },
{ 2, -1 },
{ -1, 2 },
{ 0, 3 },
{ 3, 0 },
{ 0, 10000 },
{ 10000, 0 },
};
source_y_delta = ((66 << 16) / 67) - 0x10000;
printf("delta %x, %x\n", source_y_delta, source_y_delta >> 16);
for (i = 0; i < BR_ASIZE(ranges); i++) {
LOG_INFO("Testing min=%d max=%d", ranges[i].min, ranges[i].max);
actual_min = MIN(ranges[i].min, ranges[i].max);
actual_max = MAX(ranges[i].min, ranges[i].max);
for (j = 0; j < 1000; j++) {
r = IRandomBetween(ranges[i].min, ranges[i].max);
TEST_ASSERT_GREATER_OR_EQUAL(actual_min, r);
TEST_ASSERT_LESS_OR_EQUAL(actual_max, r);
}
}
}
void test_utility_suite() {