Math: Replace rand() with mt19937

On Windows RAND_MAX is 0x7fff, which makes Rand() and RandF() far too
coarse. Use mt19937 instead so that seeded sequences reproduce the
original engine's behavior.
This commit is contained in:
kichikuou
2026-08-14 09:31:32 +09:00
parent b1f8948b74
commit d800e12f59
3 changed files with 49 additions and 4 deletions
+30 -4
View File
@@ -23,9 +23,23 @@
#define M_PI (3.14159265358979323846)
#endif
#include "system4/mt19937int.h"
#include "hll.h"
#include "vm/page.h"
static struct mt19937 mt;
static bool mt_initialized;
static uint32_t math_genrand(void)
{
if (!mt_initialized) {
mt19937_init(&mt, 4357);
mt_initialized = true;
}
return mt19937_genrand(&mt);
}
struct shuffle_table {
int id;
struct shuffle_table *next;
@@ -64,9 +78,16 @@ static float Math_Tan(float x)
return tanf(deg2rad(x));
}
static void Math_SetSeed(int seed)
{
mt19937_init(&mt, (uint32_t)seed | 1);
mt19937_genrand(&mt); // the original engine discards the first value
mt_initialized = true;
}
static void Math_SetSeedByCurrentTime(void)
{
srand(time(NULL));
Math_SetSeed(time(NULL));
}
static int Math_Min(int a, int b)
@@ -105,9 +126,14 @@ static void Math_SwapF(float *a, float *b)
//void Math_SetRandMode(int mode);
static int Math_Rand(void)
{
return math_genrand() & 0x7fffffff;
}
static float Math_RandF(void)
{
return rand() * (1.0 / (RAND_MAX + 1U));
return (float)(math_genrand() * (1.0 / 4294967296.0));
}
static void shuffle_array(int *a, int len)
@@ -192,10 +218,10 @@ HLL_LIBRARY(Math,
HLL_EXPORT(Abs, abs),
HLL_EXPORT(AbsF, fabsf),
HLL_EXPORT(Pow, powf),
HLL_EXPORT(SetSeed, srand),
HLL_EXPORT(SetSeed, Math_SetSeed),
HLL_EXPORT(SetSeedByCurrentTime, Math_SetSeedByCurrentTime),
//HLL_EXPORT(SetRandMode, Math_SetRandMode),
HLL_EXPORT(Rand, rand),
HLL_EXPORT(Rand, Math_Rand),
HLL_EXPORT(RandF, Math_RandF),
HLL_EXPORT(RandTableInit, Math_RandTableInit),
HLL_EXPORT(RandTable, Math_RandTable),
BIN
View File
Binary file not shown.
+19
View File
@@ -31,6 +31,25 @@ void test_math(void)
test_float("Math.SwapF(a, b), a", fa, 2.0);
test_float("Math.SwapF(a, b), b", fb, 1.0);
// The default seed is 4357. This must run before any other random
// number is drawn.
test_equal("Math.Rand() #1 (default seed)", Math.Rand(), 1362922229);
test_equal("Math.Rand() #2 (default seed)", Math.Rand(), 2143450242);
Math.SetSeed(12345);
test_equal("Math.Rand() #1 (seed 12345)", Math.Rand(), 2120104832);
test_equal("Math.Rand() #2 (seed 12345)", Math.Rand(), 377474682);
// SetSeed ORs the seed with 1.
Math.SetSeed(12344);
test_equal("Math.Rand() #1 (seed 12344)", Math.Rand(), 2120104832);
test_equal("Math.Rand() #2 (seed 12344)", Math.Rand(), 377474682);
Math.SetSeed(12345);
test_float("Math.RandF() #1", Math.RandF(), 0.993625);
test_float("Math.RandF() #2", Math.RandF(), 0.587888);
test_float("Math.RandF() #3", Math.RandF(), 0.857469);
Math.RandTableInit(42, 10);
for (i = 0; i < 10; i++) {
ar[Math.RandTable(42)] = 1;