One of the key features of pseudo-random number generators is that they are deterministic. Given the same starting point (seed) they will always return the same list of random numbers. This feature is exploited when you need “random” output but it needs to be the same across multiple instances of an application. Some examples would be having an on the fly procedurally generated world that multiple users interact with or having a cluster of computers track millions of particles in parallel after a simulated collision.
While in theory there should be no extra precautions needed when using random number generators across multiple platforms, in practice even a simple line of code like:
printf("%i, %i\n", rand(), rand());
Can have different results on different systems.
Function Parameter Evaluation Order
Order maters. This is a seemingly obvious statement, that the order you generate your random numbers changes their value. However when converting source code to machine code sometimes the order things are called can be flipped in C++. The question is why?
After combing through the C++ programming language standard (C++14 Standard see p.103) you find the following line:
When a function is called, each parameter (8.3.5) shall be initialized (8.5, 12.8, 12.1) with its corresponding argument. [Note: Such initializations are indeterminately sequenced with respect to each other (1.9) — end note]
The above means that it is left for the compiler to determine which order a function parameters are called. This has the potential to be disastrous if your code is compiled using multiple different compilers which is the typical case when code is ported to a different system.
Left-To-Right or Right-To-Left?
While there is the potential for functions passed as parameters to be evaluated in different orders does this really happen? In short yes. Table 1 shows the order in which parameters are evaluated depending on compiler.
OS | Compiler | Order |
Linux | gcc/g++ | left-to-right |
OSX | XCode | right-to-left |
Windows | Visual Studio | left-to-right |
Table 1: Order in which parameters are evaluated for a variety of common C++ compilers.
Table 1 indicates that if one were to port software from OSX to Windows/Linux or vice versa, one would expect that the code would not behave as expected. However it seems that the typical order evaluation on most C++ compilers is from left-to-right.
Is this an issue in other programing languages?
In most new programing languages the order of evaluation of arguments are set by standard. All of them evaluating in the same order as they are read by human, left-to-right. Table 2 shows a selection of common programming languages.
Language | Order | Source |
C11 | undefined | HERE |
<=C++14 | undefined | HERE |
C# | left-to-right | HERE |
Java | left-to-right | HERE |
Python | left-to-right | HERE |
Rust | undefined | HERE |
Table 2: Order in which parameters are evaluated for a variety of computer languages according to their programing standard. *Note this is in the standard proposal.
How do I avoid this issue?
The simple way to avoid this issue is to just force the evaluation of parameters before passing them to on to functions. As you can see here:
int rand1 = rand(); int rand2 = rand(); printf("%i, %i\n", rand1, rand2);