StrToFloat 谁错了:Delphi 或 ASE/SQL 服务器

StrToFloat and who is wrong: Delphi or ASE/SQL Server

最近发现一件奇怪的事:

的结果
var
  d: double;
begin
  d := StrToFloat('-1.79E308');

与 ASE 和 SQL 服务器通过

转换为浮点字段类型的字符串值 '-1.79E308' 不同
INSERT INTO my_table (my_float_field) VALUES (-1.79E308)

对于 Delphi 内存转储是 9A BB AD 58 F1 DC EF FF
对于 ASE/SQL select 上数据包中的服务器值是 99 BB AD 58 F1 DC EF FF

谁错了,都是服务器还是Delphi?

我们工作的前提是 StrToFloat 产生最接近提供的十进制值的可表示二进制浮点值。

您提供的两个十六进制值是相邻的。您可以看到它们在尾数中相差 1。下面是一些 Python 解码两个值的代码:

>>> import struct
>>> struct.unpack('!d', 'ffefdcf158adbb9a'.decode('hex'))[0]
-1.7900000000000002e+308
>>> struct.unpack('!d', 'ffefdcf158adbb99'.decode('hex'))[0]
-1.79e+308

请记住,Python 使用最短的有效值打印浮点值,最接近的可表示值是实际值。 ffefdcf158adbb99 解码为 Python 眼中打印为 -1.79e+308 的值,足以证明 ffefdcf158adbb99 是最接近的可表示值。换句话说,Delphi 代码给出了错误的答案。

并且,出于好奇,在相反的方向:

>>> hex(struct.unpack('<Q', struct.pack('<d', float('-1.79e308')))[0])
'0xffefdcf158adbb99L'

有趣的是,32 位 Delphi 编译器生成 ffefdcf158adbb99,而 64 位 Delphi 编译器生成 ffefdcf158adbb9a。这是一个明显的缺陷,应作为错误报告提交给 Quality Portal。