if( a == x/y )
assert( a == x/y );
Is legally allowed to trigger (!). Worse, it's also legally allowed to not trigger.That's right. The above can be legally compiled to always trigger, or never trigger, or even to sometimes trigger (although this is rare in practice).
Why? C / C++ allow floats to be stored with excess precision. And they lose that excess precision when spilled to RAM. And GCC isn't deterministic. So x/y may be pulled out as a common subexpression and spilled to a register after the first usage, and it triggers. And then the next time it isn't, and it doesn't. (Effectively, the difference between this:
temp = x/y
if( a == temp) {
spill(temp);
assert( a == temp );
}
and this: temp = x/y
if( a == temp) {
assert( a == temp );
}
Yes, it'll (generally - though the standard doesn't dictate that it will be!) be deterministic in terms of always with a given example in an single binary triggering or not triggering, but that is irrelevant, as binaries aren't cross-platform and you aren't always loading exactly the same binaries of the dynamic libraries you've linked to.You can (most of the time) work around this by manually setting FPU precision (note that you need to change the precision of both the mantissa and exponent, as otherwise you can still end up with issues). (Except that you, in C++ at least, have to work deep magic - you have to set it before main even runs, because you can end up with problems with static initialization otherwise.) And in the process losing compatibility. And finding that random code you call occasionally resets things. Or random code you don't call (a classic example: the printer driver!). And using exactly one of float or double throughout. And hoping that none of the libraries you use ever resets FPU precision for anything, or uses the other of float or double itself. (And hope that your OS properly saves / restores the FPU everywhere, though this has largely become a non-issue).
And, worst of all, you've got to hope that the compiler performs constant folding with the same level of care as you've just taken.
Look at these:
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=323
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=37845
http://yosefk.com/blog/consistency-how-to-defeat-the-purpose...
http://gafferongames.com/networking-for-game-programmers/flo...
http://www.yosoygames.com.ar/wp/2013/07/on-floating-point-de...