So I just discovered yesterday that JBox2d turns out to be wildly non-deterministic, as in, if you run the same physics simulation 10 times in a row (whether or not you’re re-starting the entire program or not), you can very easily end up with 10 completely different results, even though locally all the physics seems perfectly normal. This seems to show up more often with very complex simulations, which is not terribly surprising, chaos and all that meaning that smaller changes are magnified more with more complex systems.
Now, this was surprising to me, to say the least, because every line of code in the engine seems like it should be deterministic, as long as you’re on the same machine with the same setup - there’s not a Math.random() call in the entire thing (apart from testing code, at least), and I’ve even tested with everything set so that all Math.* calls are instead handled through lookup tables instead of through the Math library. Every other operation is straightforward pure Java, almost no library calls, and plain old arithmetic. Every container iteration (to the extent that we use containers at all, which is very little, most things are arrays) is indexed, so there should be no question about iteration order changing. Single threaded operation, of course.
I’m aware that you can never rely on floating point consistency across processors or OSes, but this was surprising to me. Results seem to keep changing even after substantial warmup, once all function compilations have stopped.
Any ideas what might be going on? Has anyone ever noticed any non-obvious non-deterministic actions in Java? I realize I could probably tag everything with strictfp and ensure floating point consistency, but it just seems like I must be missing something, if no methods are being recompiled and I’m initializing everything in the same way, then running the same simulation, how can I possibly be getting different floating point results?
Is it possible that the compiled code the JVM is producing actually leaves some operation orderings up to the CPU or something like that? In C++, typically you can at least rely on the same program to produce the same output on the same computer, but maybe the JVM is being more clever in some way?