In the gaming industry this is referred to as deterministic lockstep, and is very important for real-time networked games where the clients and server need to be in agreement about the state of physics objects (players, projectiles, deformable terrain etc).
According to Glenn Fiedler's article on Floating Point Determinism, the answer is "a resoundingly limp maybe"; if you run the same binary on the same architecture and restrict the use of features that are less well specified than basic floating-point, then you can get the same results. Otherwise, if you use different compilers, or allow your code to use SSE or 80-bit floating point, then results will vary between different executables and different machines.
Yosef Kreinin recommends:
- scanning assembler output for algebraic optimisations and applying them to your source code;
- suppressing fused multiply-add and other advanced instructions (e.g. the
sin
trigonometric function);
- and using SSE or SSE2, or otherwise setting the FPU CSR to 64-bit. (Yes, this conflicts with Glenn Fiedler's recommendation.)
And of course, test your code on multiple different machines; take hashes of intermediate outputs, so you can tell just where and when your simulations are diverging.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…