[fpc-pascal] Floating point discrepancy in x64 mode

Jonas Maebe jonas.maebe at elis.ugent.be
Fri Jul 20 13:19:26 CEST 2012


On 20 Jul 2012, at 11:59, OBones wrote:

> When I compile it with ppc386 and run it, I get the following output:
> 
> 4.16666666666667E-002
> 4.16666666666667E-002
> 
> which is totally expected.
> However, when I compile it with ppcrossx64 and run it, I get the following output:
> 
> 4.16666679084301E-002
> 4.16666666666667E-002

The reason is that Win64 (and only Win64, not other x86-64 platforms) has deprecated the use of the 80 bit 80x87 fpu. You now have to use the SSE unit for floating point math, which supports up to 64 bit double precision like most FPU's on other platforms.

Now, apart from supporting up to 80 bit precision, there's another peculiarity about the 80x87: it does not have any opcodes to perform operations at less than 80 bits precision. So a division always uses 80 bits precision, and afterwards you can truncate the result back down to whatever you need. The SSE unit on the other hand has separate opcodes for both 32 bit and 64 bit floating point math.

Now, your code has this expression:

 Result := (k+0.5)/12;

with k an integer. 0.5 and 12 can both be represented exactly using single precision, so the compiler evaluates that entire expression using single precision math. However, as mentioned on the 80x87 the addition and division will nevertheless still be evaluated using 80 bits precision due to the 80x87 limitations. On all other platforms, the expression will be evaluated entirely using 32 bit floating point math.

Possible solutions:
a) typecast one of the operands of the division to double (not that this is Delphi-incompatible)
b) Compile with -CF64 to force all floating point constants to become at least 64 bit in precision, even if they can be represented exactly using 32 bit


Jonas


More information about the fpc-pascal mailing list