I hate it when I screw up, don’t realize my mistake, think that it was
something or someone else that was in error, and then publicly blame
the party I believe to be responsible. As you may have guessed, I
figured out what I did wrong in my floating point calculations that I
blamed on gcc. It turns out that I forgot about -ffloat-store (I had
read it before, but ignored it, despite all those classes that covered
floating point arithmetic…). That option is not the default
behavior, which I was assuming/expecting. (Actually, I may have had a
secondary problem at one point in that I didn’t store floating point
expressions in temporaries before comparing them, which is required
when using -ffloat-store in order to obtain correct behavior.)
To make sure I never forget this again, here’s a simple program
demonstrating my woes of this past day:
/* Run this program like this: * * bash$ gcc -Wall -O2 precision.c -o precision * bash$ echo "10 4e-16" | ./precision * * and then again like this * * bash$ gcc -Wall -O2 -ffloat-store precision.c -o precision * bash$ echo "10 4e-16" | ./precision * * Output from this program when compiled under gcc with the former * optimization level (depends on gcc version and platform, * apparently, so this may not be what you get) is: * * i + a > i : TRUE * is_greater (i+a,i) : FALSE * inline_is_greater (i+a,i) : TRUE * * Output from this program when compiled under gcc using the latter * "optimization" level (this should be 100% reliable) is: * * i + a > i : FALSE * is_greater (i+a,i) : FALSE * inline_is_greater (i+a,i) : FALSE * * Thus, this program only reliably behaves correctly if -ffloat-store * is used. */ #include "stdio.h" inline double inline_is_greater (double a, double b) { return a > b; } double is_greater (double a, double b) { return a > b; } int main () { int i; double a; double b; scanf ("%d %lf", &i;, &a;); b = i+a; printf ("i + a > i : %s\n", (b > i) ? "TRUE" : "FALSE"); printf ("is_greater (i+a,i) : %s\n", is_greater (i+a,i) ? "TRUE" : "FALSE"); printf ("inline_is_greater (i+a,i) : %s\n", inline_is_greater (i+a,i) ? "TRUE" : "FALSE"); return 0; }
Now, I just need to decide whether to turn on -ffloat-store for a
small section of my code (and how to do so–I’m fearing ugly Makefile
hacks and being forced to split certain files up that I don’t really
like splitting), or to leave it on for my entire code. My code runs
slightly faster if I don’t turn it on and it doesn’t hurt to have that
extra accuracy in places other than one or two critical sections, but
it does make it harder to compare results if the code is run across
multiple architectures (and even on the same one with different levels
of optimization)…