One of my 2023 resolutions is to get back in to some writing. I have a homemade blog antongerdelan.net/blog but I’d like to give Substack a try. This post is a bit of an experiment with using Substack, so the content is somewhat simple today, but is a hint at what directions it might take.
rand() Implementations are Inconsistent
I’m building a Minecraft-esque hobby project, which uses a lot of random numbers for generating the voxel world, and for doing various other interesting things at run-time.
I’m using the C programming language, which has a pseudo-random number generator called rand()
in the stdlib.h
library. The numbers you get out from this function differ on different platforms, which is not ideal, so I created a very simple drop-in replacement:
#define APG_RAND_MAX 32767 // I think this is what Microsoft uses.
typedef unsigned long int apg_rand_t;
static apg_rand_t _seed = 1;
void apg_srand( apg_rand_t seed ) { _seed = seed; }
int apg_rand( void ) {
_seed = _seed * 1103515245 + 12345;
return (unsigned int)(_seed / ((APG_RAND_MAX + 1) * 2)) % (APG_RAND_MAX + 1);
}
If I recall, I took the values and logic from a guide implementation. You can create a better pseudo-random sequence, but for my hobby program this was fine.
Multi-Threaded Path-Finding
At some point I added multi-threaded AI simulation for characters in the world, which helped organise the execution of 3D path-finding without disrupting the performance of the game.

The problem with the above code, as with rand()
from the standard library, is that it uses a global variable to maintain state, which is fine for old-school single-threaded applications, but if I want to keep using it within worker threads then I will get race conditions.
I was going to replace my trivial copy of rand()
with a more sophisticated function, but I decided instead on recreating the re-entrant rand_r()
, also from stdlib.h
. It is somewhat imprecise, as it admits in the man-page, but I thought that it would be more interesting to have the full set of drop-in functions.
int apg_rand_r( apg_rand_t* seed_ptr ) {
assert( seed_ptr );
if ( !seed_ptr ) { return 0; }
*seed_ptr = *seed_ptr * 1103515245 + 12345;
return (unsigned int)(*seed_ptr / ((APG_RAND_MAX + 1) * 2)) % (APG_RAND_MAX + 1);
}
This has the same logic as the previous function, but the seed is user-supplied. So each thread will have its own seed variable that it passes between calls to apg_rand_r()
. An example use follows:
apg_rand_t initial_seed = time( NULL ); // Equiv. to srand().
apg_rand_t working_sequence = initial_seed;
int random_result = rand_r( &working_sequence );
Floating Point rand()
A random number between 0.0 and 1.0 is quite useful for procedural generation, so I also added floating point convenience variants of the rand()
functions:
float apg_randf( void ) {
return (float)apg_rand() / (float)APG_RAND_MAX;
}
float apg_randf_r( apg_rand_t* seed_ptr ) {
assert( seed_ptr );
if ( !seed_ptr ) { return 0.0f; }
return (float)apg_rand_r( seed_ptr ) / (float)APG_RAND_MAX;
}
I think I got this idea from a post about how Minecraft was created, which I would link, but it was a long time ago, and I have old-person grade memory now!
Conventions and Caveats
I tried to stay as close to the interface of rand()
functions as possible, such that I could use these functions as drop-in replacements to existing code.
The original functions use
unsigned
seeds, but I wanted to useunsigned long
. I just made this atypedef
in case I needed to switch it back tounsigned
for backwards compatibility.Integers in interfaces are vulnerable to precision and sign accidental misuse, so I would usually put this sort of parameter in a struct to provide some harder type protection. Not this time though.
I have these functions in my apg.h little snippet library. Type and function names are preceded by
apg_
. It’s an unofficial convention to use a prefix for C libraries, since C doesn’t have namespaces. Likewise, constants are prefixed byAPG_
. Types I post-fix with_t
for type, which is sort of naughty because POSIX claims to reserve that exclusively, but I’m not fussed about that.You might notice, despite functions returning an
int
, that they are cast tounsigned int
first. This is done deliberately to avoid returning negative numbers. The functions should probably just returnunsigned int
. This wasn’t changed for consistency with the originals.
Thoughts on Substack
I can’t see any obvious way to change the typeface and theme yet. If you’re reading this in a sans-serif font then I figured at least some of it out!
It’s a bit unresponsive to type into the web interface, which is quite frustrating, and it doesn’t seem to pick up every keystroke when I type quickly.
If this works well I might replace my crummy old blog. I have a few ideas for subject streams to write about that might be of value to readers. I’d be interested in getting a feel for the reach and accessibility versus publishing books, for example. Text-to-speech for listeners, and text size adjustment for readers could be a big win.
I’ve never been a huge fan of video tutorials since they are very time-intensive to create and also to listen to, compared to written text. And you can follow code much more easily than from a screen recording. Perhaps this could be a useful middle ground, or where a mixed approach would work well.
If you’d like to see more of this sort of thing (but maybe more useful!) subscribe/share/say hi!