In a 664 bit app, If I compare a floating point constant to a value obtained from StrToFloat() for the same "value" I get a different results. For example:
procedure foo;
const
d1 = 0.6694716
d3: double = 0.6694716
var
d2: double;
begin
d2 := StrToFloat('0.6694716');
if d1 = d2 then
beep;
if d1 = d3 then
beep;
if d2 = d3 then
beep;
end;
The d1 and d3 have a hex value of $B47339B4 while d2 has a hex value of $B47339B3. While they are "equal" for a comparison. They technically are not the same. From what I can tell, the constants d1 and d2 are wrong. Perhaps the compiler uses the FPU and this is due to rounding?
Short of making all my constants as strings and converting them at run time. Anyone know of a work around for this?
CodePudding user response:
Float literals in Delphi are Extended by default. In 64 bits, that shouldn't make any difference, but in 32 bits it does. My guess is that the parser still internally represents float literals as a 10 byte float(extended), and then the 64 bits compiler "round it down" to 8 bytes(double) when compiling.
If my hypothesis is right, there might be nothing that can be done to circumvent that.
EDIT
Delphi does the following conversion
- Double(3FE56C4FB47339B3) converts to Extended(3FFEAB627DA399CD9800)
- Double(3FE56C4FB47339B4) converts to Extended(3FFEAB627DA399CDA000)
- 0.6694716 is Extended(3FFEAB627DA399CD9C00)
CodePudding user response:
Disgusting as it is, I put the const as string values and the convert them to double in the unit initialization. That way we get double not extended math. This seems to work. I expect it will not work with 32-bit.
function HexToDouble(const val: uint64): double; inline;
begin
result := Pdouble(@val)^;
end;
//use
D1 := HexToDouble($3fe56c4fb47339b3);