Skip to content

Commit

Permalink
Replace statistically weak, slow and platform dependent rand() with X…
Browse files Browse the repository at this point in the history
…orshiro64** everywhere
  • Loading branch information
Novum committed Jan 6, 2025
1 parent 1cf295c commit e692608
Show file tree
Hide file tree
Showing 16 changed files with 150 additions and 147 deletions.
10 changes: 5 additions & 5 deletions Quake/cl_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -741,7 +741,7 @@ void CL_RelinkEntities (void)
AngleVectors (ent->angles, fv, rv, uv);

VectorMA (dl->origin, 18, fv, dl->origin);
dl->radius = 200 + (rand () & 31);
dl->radius = 200 + (COM_Rand () & 31);
dl->minlight = 32;
dl->die = cl.time + 0.1;

Expand All @@ -760,21 +760,21 @@ void CL_RelinkEntities (void)
dl = CL_AllocDlight (i);
VectorCopy (ent->origin, dl->origin);
dl->origin[2] += 16;
dl->radius = 400 + (rand () & 31);
dl->radius = 400 + (COM_Rand () & 31);
dl->die = cl.time + 0.001;
}
if (ent->effects & EF_DIMLIGHT)
{
dl = CL_AllocDlight (i);
VectorCopy (ent->origin, dl->origin);
dl->radius = 200 + (rand () & 31);
dl->radius = 200 + (COM_Rand () & 31);
dl->die = cl.time + 0.001;
}
if (ent->effects & EF_QEX_QUADLIGHT)
{
dl = CL_AllocDlight (i);
VectorCopy (ent->origin, dl->origin);
dl->radius = 200 + (rand () & 31);
dl->radius = 200 + (COM_Rand () & 31);
dl->die = cl.time + 0.001;
dl->color[0] = 0.25f;
dl->color[1] = 0.25f;
Expand All @@ -784,7 +784,7 @@ void CL_RelinkEntities (void)
{
dl = CL_AllocDlight (i);
VectorCopy (ent->origin, dl->origin);
dl->radius = 200 + (rand () & 31);
dl->radius = 200 + (COM_Rand () & 31);
dl->die = cl.time + 0.001;
dl->color[0] = 1.0f;
dl->color[1] = 0.25f;
Expand Down
4 changes: 2 additions & 2 deletions Quake/cl_parse.c
Original file line number Diff line number Diff line change
Expand Up @@ -528,7 +528,7 @@ static void CL_EntitiesDeltaed (void)
if (model->synctype == ST_FRAMETIME)
ent->syncbase = -cl.time;
else if (model->synctype == ST_RAND)
ent->syncbase = (float)(rand () & 0x7fff) / 0x7fff;
ent->syncbase = (float)(COM_Rand () & 0xffffff) / 0xffffff;
else
ent->syncbase = 0.0;
}
Expand Down Expand Up @@ -1265,7 +1265,7 @@ static void CL_ParseUpdate (int bits)
if (model)
{
if (model->synctype == ST_RAND)
ent->syncbase = (float)(rand () & 0x7fff) / 0x7fff;
ent->syncbase = (float)(COM_Rand () & 0xffffff) / 0xffffff;
else
ent->syncbase = 0.0;
}
Expand Down
12 changes: 6 additions & 6 deletions Quake/cl_tent.c
Original file line number Diff line number Diff line change
Expand Up @@ -165,11 +165,11 @@ void CL_ParseTEnt (void)
pos[2] = MSG_ReadCoord (cl.protocolflags);
if (PScript_RunParticleEffectTypeString (pos, NULL, 1, "TE_SPIKE"))
R_RunParticleEffect (pos, vec3_origin, 0, 10);
if (rand () % 5)
if (COM_Rand () % 5)
S_StartSound (-1, 0, cl_sfx_tink1, pos, 1, 1);
else
{
rnd = rand () & 3;
rnd = COM_Rand () & 3;
if (rnd == 1)
S_StartSound (-1, 0, cl_sfx_ric1, pos, 1, 1);
else if (rnd == 2)
Expand All @@ -185,11 +185,11 @@ void CL_ParseTEnt (void)
if (PScript_RunParticleEffectTypeString (pos, NULL, 1, "TE_SUPERSPIKE"))
R_RunParticleEffect (pos, vec3_origin, 0, 20);

if (rand () % 5)
if (COM_Rand () % 5)
S_StartSound (-1, 0, cl_sfx_tink1, pos, 1, 1);
else
{
rnd = rand () & 3;
rnd = COM_Rand () & 3;
if (rnd == 1)
S_StartSound (-1, 0, cl_sfx_ric1, pos, 1, 1);
else if (rnd == 2)
Expand Down Expand Up @@ -356,7 +356,7 @@ void CL_UpdateTEnts (void)
num_temp_entities = 0;

if (cl.paused)
srand ((int)(cl.time * 1000)); // johnfitz -- freeze beams when paused
COM_SeedRand ((uint64_t)(cl.time * 1000)); // johnfitz -- freeze beams when paused

// update lightning
for (i = 0, b = cl_beams; i < MAX_BEAMS; i++, b++)
Expand Down Expand Up @@ -405,7 +405,7 @@ void CL_UpdateTEnts (void)
ent->model = b->model;
ent->angles[0] = pitch;
ent->angles[1] = yaw;
ent->angles[2] = rand () % 360;
ent->angles[2] = COM_Rand () % 360;

// johnfitz -- use j instead of using i twice, so we don't corrupt memory
for (j = 0; j < 3; j++)
Expand Down
44 changes: 44 additions & 0 deletions Quake/common.c
Original file line number Diff line number Diff line change
Expand Up @@ -3163,3 +3163,47 @@ size_t LOC_Format (const char *format, const char *(*getarg_fn) (int idx, void *

return written;
}

/*
================
Initial state picked randomly, can't be 0.
================
*/
static uint32_t xorshiro_state[2] = {0xcdb38550, 0x720a8392};

This comment has been minimized.

Copy link
@vsonnier

vsonnier Jan 6, 2025

Collaborator

Shouldn't this global state be THREAD_LOCAL ?

This comment has been minimized.

Copy link
@vsonnier

vsonnier Jan 7, 2025

Collaborator

Update : Nervermind, it probably doesn't matter much if in rare cases xorshiro_state is updated conccurently by multiple threads, after all this is about generating random numbers...


/*
=================
COM_SeedRand
=================
*/
void COM_SeedRand (uint64_t seed)
{
// SplitMix64
uint64_t z = (seed + 0x9e3779b97f4a7c15);
z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9;
z = (z ^ (z >> 27)) * 0x94d049bb133111eb;
uint64_t state = z ^ (z >> 31);
xorshiro_state[0] = (uint32_t)state;
xorshiro_state[1] = (uint32_t)(state >> 32);
}

/*
=================
COM_Rand
=================
*/
static inline uint32_t rotl (const uint32_t x, int k)
{
return (x << k) | (x >> (32 - k));
}
uint32_t COM_Rand ()
{
// Xorshiro64**
const uint32_t s0 = xorshiro_state[0];
uint32_t s1 = xorshiro_state[1];
const uint32_t result = rotl (s0 * 0x9E3779BB, 5) * 5;
s1 ^= s0;
xorshiro_state[0] = rotl (s0, 26) ^ s1 ^ (s1 << 9);
xorshiro_state[1] = rotl (s1, 13);
return result;
}
4 changes: 4 additions & 0 deletions Quake/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,10 @@ const char *LOC_GetString (const char *key);
qboolean LOC_HasPlaceholders (const char *str);
size_t LOC_Format (const char *format, const char *(*getarg_fn) (int idx, void *userdata), void *userdata, char *out, size_t len);

void COM_SeedRand (uint64_t seed);
uint32_t COM_Rand (void);
#define COM_RAND_MAX UINT32_MAX

//============================================================================

// QUAKEFS
Expand Down
51 changes: 3 additions & 48 deletions Quake/gl_heap.c
Original file line number Diff line number Diff line change
Expand Up @@ -901,50 +901,6 @@ static void TestHeapConsistency (glheap_t *heap)
stats->num_allocations == (stats->num_small_allocations + stats->num_block_allocations + stats->num_dedicated_allocations), "Invalid alloc counter");
}

/*
=================
Xorshiro128Seed
=================
*/
static uint64_t SplitMix64 (uint64_t *seed)
{
uint64_t z = (*seed += 0x9e3779b97f4a7c15);
z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9;
z = (z ^ (z >> 27)) * 0x94d049bb133111eb;
return z ^ (z >> 31);
}
void Xorshiro128Seed (uint64_t seed, uint32_t state[4])
{
uint64_t tmp = SplitMix64 (&seed);
state[0] = (uint32_t)tmp;
state[1] = (uint32_t)(tmp >> 32);
tmp = SplitMix64 (&seed);
state[2] = (uint32_t)tmp;
state[3] = (uint32_t)(tmp >> 32);
}

/*
=================
Xorshiro128Next
=================
*/
static inline uint32_t rotl (const uint32_t x, int k)
{
return (x << k) | (x >> (32 - k));
}
uint32_t Xorshiro128Next (uint32_t *state)
{
const uint32_t result = rotl (state[1] * 5, 7) * 9;
const uint32_t t = state[1] << 9;
state[2] ^= state[0];
state[3] ^= state[1];
state[1] ^= state[2];
state[0] ^= state[3];
state[2] ^= t;
state[3] = rotl (state[3], 11);
return result;
}

/*
=================
GL_HeapTest_f
Expand All @@ -963,8 +919,7 @@ void GL_HeapTest_f (void)
Atomic_StoreUInt32 (&num_allocations, 0);
glheap_t *test_heap = GL_HeapCreate (TEST_HEAP_SIZE, TEST_HEAP_PAGE_SIZE, 0, VULKAN_MEMORY_TYPE_NONE, "Test Heap");
TestHeapCleanState (test_heap);
uint32_t rand_state[4] = {0, 0, 0, 0};
Xorshiro128Seed (0, rand_state);
COM_SeedRand (0);
TEMP_ALLOC_ZEROED (glheapallocation_t *, allocations, NUM_ALLOCS_PER_ITERATION);
for (int j = 0; j < NUM_ITERATIONS; ++j)
{
Expand All @@ -976,9 +931,9 @@ void GL_HeapTest_f (void)
for (int i = k; i < NUM_ALLOCS_PER_ITERATION; i += STRIDE)
{
// Exponential distribution (more small allocations)
const double exponential_dist_size = powf ((double)Xorshiro128Next (rand_state) / (double)UINT32_MAX, 5.0);
const double exponential_dist_size = powf ((double)COM_Rand () / (double)COM_RAND_MAX, 5.0);
const VkDeviceSize size = (VkDeviceSize)((double)(MAX_ALLOC_SIZE - 1) * exponential_dist_size) + 1;
const double exponential_dist_alignment = powf ((double)Xorshiro128Next (rand_state) / (double)UINT32_MAX, 10.0);
const double exponential_dist_alignment = powf ((double)COM_Rand () / (double)COM_RAND_MAX, 10.0);
const VkDeviceSize alignment = 1ull << (uint32_t)(exponential_dist_alignment * (double)MAX_ALIGNMENT_POW2);
HEAP_TEST_ASSERT (allocations[i] == NULL, "allocation is not NULL");

Expand Down
4 changes: 2 additions & 2 deletions Quake/hash_map.c
Original file line number Diff line number Diff line change
Expand Up @@ -343,7 +343,7 @@ HashMap_BasicTest
*/
static void HashMap_StressTest (void)
{
srand (0);
COM_SeedRand (0);
const int TEST_SIZE = 10000;
TEMP_ALLOC (int64_t, keys, TEST_SIZE);
hash_map_t *map = HashMap_Create (int64_t, int32_t, &HashInt64, NULL);
Expand All @@ -355,7 +355,7 @@ static void HashMap_StressTest (void)
}
for (int i = TEST_SIZE - 1; i > 0; --i)
{
const int swap_index = rand () % (i + 1);
const int swap_index = COM_Rand () % (i + 1);
const int temp = keys[swap_index];
keys[swap_index] = keys[i];
keys[i] = temp;
Expand Down
2 changes: 1 addition & 1 deletion Quake/host.c
Original file line number Diff line number Diff line change
Expand Up @@ -874,7 +874,7 @@ void _Host_Frame (double time)
return; // something bad happened, or the server disconnected

// keep the random time dependent
rand ();
COM_Rand ();

// decide the simulation time
accumtime += host_netinterval ? CLAMP (0, time, 0.2) : 0; // for renderer/server isolation
Expand Down
2 changes: 1 addition & 1 deletion Quake/host_cmd.c
Original file line number Diff line number Diff line change
Expand Up @@ -879,7 +879,7 @@ static void Host_Randmap_f (void)
return;
}

randlevel = (rand () % numlevels);
randlevel = (COM_Rand () % numlevels);

for (level = extralevels, i = 0; level; level = level->next, i++)
{
Expand Down
2 changes: 1 addition & 1 deletion Quake/menu.c
Original file line number Diff line number Diff line change
Expand Up @@ -2540,7 +2540,7 @@ void M_Menu_Quit_f (void)
m_quit_prevstate = m_state;
m_state = m_quit;
m_entersound = true;
msg_number = rand () & 7;
msg_number = COM_Rand () & 7;
}
else
{
Expand Down
4 changes: 2 additions & 2 deletions Quake/pr_cmds.c
Original file line number Diff line number Diff line change
Expand Up @@ -536,7 +536,7 @@ static void PF_random (void)
{
// don't return 1 (it would break array[random()*array.length];
// don't return 0 either, it would break the self.nextthink = time+random()*foo; lines in walkmonster_start, resulting rarely in statue-monsters.
G_FLOAT (OFS_RETURN) = (rand () & 0x7fff) / ((float)0x08000) + (0.5 / 0x08000);
G_FLOAT (OFS_RETURN) = (COM_Rand () & 0x7fff) / ((float)0x08000) + (0.5 / 0x08000);

if (qcvm->argc)
{
Expand Down Expand Up @@ -1755,7 +1755,7 @@ void PR_spawnfunc_misc_model (edict_t *self)
self->v.model = PR_SetEngineString ("*null");

if (self->v.angles[1] < 0) // mimic AD. shame there's no avelocity clientside.
self->v.angles[1] = (rand () * (360.0f / (float)RAND_MAX));
self->v.angles[1] = (COM_Rand () * (360.0f / (float)COM_RAND_MAX));

// make sure the model is precached, to avoid errors.
G_INT (OFS_PARM0) = self->v.model;
Expand Down
14 changes: 7 additions & 7 deletions Quake/pr_ext.c
Original file line number Diff line number Diff line change
Expand Up @@ -2579,11 +2579,11 @@ static void PF_cl_te_spike (void)

if (PScript_RunParticleEffectTypeString (pos, NULL, 1, "TE_SPIKE"))
R_RunParticleEffect (pos, vec3_origin, 0, 10);
if (rand () % 5)
if (COM_Rand () % 5)
S_StartSound (-1, 0, S_PrecacheSound ("weapons/tink1.wav"), pos, 1, 1);
else
{
int rnd = rand () & 3;
int rnd = COM_Rand () & 3;
if (rnd == 1)
S_StartSound (-1, 0, S_PrecacheSound ("weapons/ric1.wav"), pos, 1, 1);
else if (rnd == 2)
Expand All @@ -2609,11 +2609,11 @@ static void PF_cl_te_superspike (void)
if (PScript_RunParticleEffectTypeString (pos, NULL, 1, "TE_SUPERSPIKE"))
R_RunParticleEffect (pos, vec3_origin, 0, 20);

if (rand () % 5)
if (COM_Rand () % 5)
S_StartSound (-1, 0, S_PrecacheSound ("weapons/tink1.wav"), pos, 1, 1);
else
{
int rnd = rand () & 3;
int rnd = COM_Rand () & 3;
if (rnd == 1)
S_StartSound (-1, 0, S_PrecacheSound ("weapons/ric1.wav"), pos, 1, 1);
else if (rnd == 2)
Expand Down Expand Up @@ -3926,9 +3926,9 @@ static void PF_randomvector (void)
vec3_t temp;
do
{
temp[0] = (rand () & 32767) * (2.0 / 32767.0) - 1.0;
temp[1] = (rand () & 32767) * (2.0 / 32767.0) - 1.0;
temp[2] = (rand () & 32767) * (2.0 / 32767.0) - 1.0;
temp[0] = (COM_Rand () & 0xffffff) * (2.0 / (float)0xffffff) - 1.0;
temp[1] = (COM_Rand () & 0xffffff) * (2.0 / (float)0xffffff) - 1.0;
temp[2] = (COM_Rand () & 0xffffff) * (2.0 / (float)0xffffff) - 1.0;
} while (DotProduct (temp, temp) >= 1);
VectorCopy (temp, G_VECTOR (OFS_RETURN));
}
Expand Down
Loading

0 comments on commit e692608

Please sign in to comment.