Yes, these are very subtle. For example, floating point computation has different precision depending on the machine.
This might lead to small differences in the game state, which grow over time (chaos theory yay). It is really hard to hunt such bugs. The fix might look like this:
- double result = x * y * z;
+ double tmp = x * y;
+ double result = tmp * z;
The intermediate value x*y is rounded to double precision afterwards, whereas it had machine precision before.
(disclaimer: second hand war story from OpenTTD, might not be entirely accurate)
Indeed, if determinism is very important, fixed-point arithmetics should be preferred over floating point arithmetics - at least in the game engine, for the rendering floating point should be fine.
Note that fixed-point arithmetics is almost identical to integer arithmetics, thus easy to implement. If you define your physical units small enough (e.g. velocity as pixels/ms instead of pixels/s), then you can use integer arithmetics right away without any confusion.
One minor drawback is that you don't have easy access to cos(), sin(), sqrt(), etc. without going through floating point. However, you usually don't need those in the game engine anyway. For instance, instead of "sqrt(xx + yy) < r", just write "xx + yy < r*r".
The major drawback is that you now might have to deal with integer overflows (and underflows). You should deal with them in floating point, too, but these are more unlikely there. One might think that this won't destroy determinism if you are using e.g. always 32 bit integers on all platforms, but note that some kinds of (signed) underflows or overflows are technically undefined, at least in the C standard, so some compilers might do optimizations that lead to different underflow/overflow results than expected.
Floating point arithmetic is deterministic if you are careful enough:
> "I work at Gas Powered Games and i can tell you first hand that floating point math is deterministic. You just need the same instruction set and compiler and of course the user’s processor adheres to the IEEE754 standard, which includes all of our PC and 360 customers. The engine that runs DemiGod, Supreme Commander 1 and 2 rely upon the IEEE754 standard."
There seem to be conflicting opinions from game developers about whether you can coax determinism out of IEEE 754 floating point, if you're careful about it. From what I've read, the IEEE 754-2008 revision is supposed to take the goal of reproducible results more seriously as well, but I'm not sure how widely implemented or reliable its efforts in that department are.
(disclaimer: second hand war story from OpenTTD, might not be entirely accurate)