Komputery oszukują
Niestety, w trakcie naszych zajęć, dzięki spostrzegawczości i dociekliwości niektórych studentek, wyszło na jaw, że współczesne PC-ty (np. architektura Intela zwana IA32) OSZUKUJĄ i ... liczą dokładniej niż im wolno.
Ciekawy artykuł na ten temat napisał w maju 2008 David Monniaux.
Oto fragment z tego artykułu:
...the final result of the computations depend on how the compiler allocates registers, since temporaries (and possibly variables) will incur or not incur rounding whether or not they are spilt to main memory.
As an example, the following program compiled with gcc 4.0.1 under Linux will print 10308 (1E308):
double v = 1E308;
double x = (v * v) / v;
printf("%g %d\n", x, x==v);
How is that possible? v * v done in double precision will overflow, and thus yield +∞ , and the final result should be +∞. However, since all computations are performed in extended precision, with a larger exponent range, the computations do not overflow. If we use the -ffloat-store option, which forces gcc to store floating-point variables in memory, we obtain +∞.
Koniec cytatu z artykułu Davida Monniaux, gdzie opisanych jest jeszcze sporo innych ciekawych, niegroźnych ale i koszmarnych "pułapek" na programistów.
A w opisie opcji kompilatora gcc (4.1.2) czytamy:
-ffloat-store
Do not store floating point variables in registers, and inhibit other options that might change whether a floating point value is taken from a register or memory.
This option prevents undesirable excess precision on machines such as the 68000 where the floating registers (of the 68881) keep more precision than a double is supposed to have. Similarly for the x86 architecture. For most programs, the excess precision does only good, but a few programs rely on the precise definition of IEEE floating point. Use -ffloat-store for such programs, after modifying them to store all pertinent intermediate computations into variables.
Krótko mówiąc bez tej opcji kompilator gcc nie przestrzega "IEEE-754 Standard for Floating-Point Arithmetic" (i takie jest jego zachowanie domyślne) !
Dalej w opisie opcji kompilatora gcc (4.1.2) czytamy też:
-mfpmath=unit
Generate floating point arithmetics for selected unit
unit. The choices for unit are:
Use the standard 387 floating point coprocessor present majority of chips and emulated otherwise. Code compiled with this option will run almost everywhere. The temporary results are computed in 80bit precision instead of precision specified by the type resulting in slightly different results compared to most of other chips. See -ffloat-store for more detailed description.
This is the default choice for i386 compiler.
Use scalar floating point instructions present in the SSE instruction set. This instruction set is supported by Pentium3 and newer chips, in the AMD line by Athlon-4, Athlon-xp and Athlon-mp chips. The earlier version of SSE instruction set supports only single precision arithmetics, thus the double and extended precision arithmetics is still done using 387. Later version, present only in Pentium4 and the future AMD x86-64 chips supports double precision arithmetics too.
For the i386 compiler, you need to use -march=cpu-type, -msse or -msse2 switches to enable SSE extensions and make this option effective. For the x86-64 compiler, these extensions are enabled by default.
The resulting code should be considerably faster in the majority of cases and avoid the numerical instability problems of 387 code, but may break some existing code that expects temporaries to be 80bit.
This is the default choice for the x86-64 compiler.
Z przykrością muszę stwierdzić, że znalazłem już pierwszy program (jeden z moich używanych od lat programów obliczeniowych), który nie działa poprawnie, jeśli skompilować go bez opcji " -ffloat-store ".
≡
Ostatnia aktualizacja: 03.10.2014, 19:59.