Przeprowadziłem małe śledztwo.
Specyfikacja standardu ECMA-335 (w której istnienie wątpią niektórzy hejterzy MS, bo w końcu niemożliwe, żeby CLI miało otwartą i powszechnie dostępną specyfikację) stwierdza w części I, w rozdziale 12.3.1, że:
Storage locations for floating-point numbers (statics, array elements, and fields of classes) are of fixed size. The supported storage sizes are float32 and float64. Everywhere else (on the evaluation stack, as arguments, as return types, and as local variables) floating-point numbers are represented using an internal floating-point
type. In each such instance, the nominal type of the variable or expression is either float32or float64, but its value can be represented internally with additional range and/or precision. The size of the internal floatingpoint representation is implementation-dependent, can vary, and shall have precision at least as great as that of the variable or expression being represented. An implicit widening conversion to the internal representation from float32 or float64 is performed when those types are loaded from storage. The internal representation is typically the native size for the hardware, or as required for efficient implementation of an operation. The internal representation shall have the following characteristics:
• The internal representation shall have precision and range greater than or equal to the nominal
type.
• Conversions to and from the internal representation shall preserve value.
A co z tego wynika:
This design allows the CLI to choose a platform-specific high-performance representation for floating-point numbers until they are placed in storage locations. For example, it might be able to leave floating-point variables in hardware registers that provide more precision than a user has requested. At the same time, CIL generators can force operations to respect language-specific rules for representations through the use of conversion instructions.
Co jest potwierdzone w specyfikacji C#:
Floating-point operations may be performed with higher precision than the result type of the operation. For example, some hardware architectures support an "extended" or "long double" floating-point type with greater range and precision than the double type, and implicitly perform all floating-point operations using this higher precision type.
Kończąc wyjaśnienia - obliczenia na floatach w x86 korzystają z 80 bitowego FPU, zaś te same obliczenia na x64 korzystają z 128 bitowego SSE.
Przynajmniej tak to rozumiem: http://www.manicai.net/comp/debugging/fpudiff/
Kompilacja w trybie x86 zapewne wymusza użycie obliczeń na FPU zawsze i wszędzie, więc daje wyniki liczone z mniejszą precyzją.
Nie znam Javy (nie mam IQ programisty Delphi), ale na tyle ile zrozumiałem z Wiki i Osiłka, to ten sam efekt (mniejszej precyzji obliczeń) daje użycie strictfp
w Javie. Niemniej jednak moi szpiedzy z Gdańska donoszą, że Java dla kodu z pierwszego posta zwraca identyczne wyniki na x86 i x64 bez względu na użycie tego słowa kluczowego, więc nie mam pojęcia jak jest naprawdę i po co ono właściwie jest, skoro nie zmienia wyniku.
Reasumując, specyfikacja IEEE 754 jest do d**y, bo nie precyzuje jak mają być przeprowadzane obliczenia i stąd te różnice. ;)