views:

281

answers:

3

When I run the exact same code performing the exact same floating point calculation (using doubles) compiled on Windows and Solaris, I get slightly different results.

I am aware that the results are not exact due to rounding errors. However I would have expected the rounding errors to be platform-independent, thereby giving be the same (slightly incorrect) result on both platforms, which is not the case.

Is this normal, or do I have another problem in my code?

+6  A: 

On x86, usually most calculations happen with 80-bit quantities, unless otherwise forced to be double-precision. Most other architectures I know of do all calculations in double-precision (again, unless otherwise overridden).

I don't know if you're running Solaris on SPARC or x86, but if the former, then I highly suspect that to be the cause of the difference.

Chris Jester-Young
If this is Solaris x86, this 80-bit representation still is likely to be the cause of the difference. Floating-point computations on x86 only happen with 80-bit quantities if it's using the (built-in) x87 math coprocessor; if it's using the newer SSE vector unit, they're normal 64-bit doubles. GCC will tend by default to use the x87 for compatibility with old processors; any other compiler will use the SSE unit because it's faster even for things that aren't vectors.
Brooks Moses
@Brooks: Thanks! Very nice clarification.
Chris Jester-Young
You're welcome! By the way, http://gcc.gnu.org/bugzilla/show_bug.cgi?id=323 is a pretty exhaustive discussion of this. (It's also the first Google result for 'gcc floating point bug', which will tell you how often people run into this issue!)
Brooks Moses
It is fixable, set the PC field of the FPU control word to double precision (53 bits). Intel manual chapter 8.1.5.2. Check your CRT implementation for something resembling _controlfp or _control87.
Hans Passant
+1  A: 

The subject of your question suggests that it might depend on the compiler. It might, but the fact that you are running on different hardware (assuming your Solaris is not x86) suggests a much more likely reason for the difference - the difference in hardware itself.

Different hardware platforms might use completely different hardware devices (FPUs, CPUs) to perform floating-point calculations, arriving at different results.

Moreover, often the FPU units are configurable by some persistent settings, like infinity model, rounding mode etc. Different hardware might have different default setup. Compiler will normally generate the code that will initialize the FPU at program startup, by that initial setup can be different as well.

Finally, different implementations of C++ language might implement floating-point semantics differently, so you might even get different results from different C++ compilers of the same hardware.

AndreyT
A: 

I believe that under Windows/x86, your code will run with the x87 precision already set to 53 bits (double precision), though I'm not sure exactly when this gets set. On Solaris/x86 the x87 FPU is likely to be using its default precision of 64 bits (extended precision), hence the difference.

There's a simple check you can do to detect which precision (53 bits or 64 bits) is being used: try computing something like 1e16 + 2.9999, while being careful to avoid compiler constant-folding optimizations (e.g., define a separate add function to do the addition, and turn off any optimizations that might inline functions). When using 53-bit precision (SSE2, or x87 in double-precision mode) this gives 1e16 + 2; when using 64-bit precision (x87 in extended precision mode) this gives 1e16 + 4. The latter result comes from an effect called 'double rounding', where the result of the addition is rounded first to 64 bits, and then to 53 bits. (Doing this calculation directly in Python, I get 1e16 + 4 on 32-bit Linux, and 1e16+2 on Windows, for exactly the same reason.)

Here's a very nice article (that goes significantly beyond the oft-quoted Goldberg's "What every computer scientist should know...") that explains some of the problems arising from the use of the x87 FPU:

http://hal.archives-ouvertes.fr/docs/00/28/14/29/PDF/floating-point-article.pdf

Mark Dickinson