StrToFloat 无法报告德尔福 64 位中的无效浮点数



以下代码,它尝试转换远超出双精度范围的值

StrToFloat('1e99999999')

使用Windows 32 位编译器在 Delphi 10.2r3 中正确报告不正确的浮点值,但在使用 Window 64 位编译器编译时,它会静默返回 0(零)。

有没有办法让 StrToFloat 在浮点值不正确时报告错误?

我已经尝试过TArithmeticException.exOverflow,但这在这种情况下没有效果。

我也尝试过TArithmeticException.exPrecision,但它在许多常见的近似情况下触发(f.i.它在转换"1e9"时触发)。

德尔福 10.2 更新 3 注意到问题

附录:为了解决这个问题,我已经开始了一个字符串到双重转换的洁净室替代实现,带有测试的初始版本可以在 dwscript commit 2ba1d4a 中找到

这是所有使用 PUREPASCAL 版本的 DelphiStrToFloat版本中都存在的缺陷。这映射到InternalTextToExtended,其指数如下所示:

function ReadExponent: SmallInt;
var
LSign: SmallInt;
begin
LSign := ReadSign();
Result := 0;
while LCurrChar.IsDigit do
begin
Result := Result * 10;
Result := Result + Ord(LCurrChar) - Ord('0');
NextChar();
end;
if Result > CMaxExponent then
Result := CMaxExponent;
Result := Result * LSign;
end;

问题是位置

if Result > CMaxExponent then

此测试旨在进入循环内部,在此代码的 asm x86 版本中也是如此。如上所述,由于最大指数测试在循环之外,16 位有符号整数结果值对于99999999的指数来说太小了。读取指数时,Result中的值溢出,变为负数。因此,对于您的示例,事实证明使用的是-7937指数而不是99999999.自然,这会导致值为零。

这是一个明显的错误,我已经提交了一份错误报告:RSP-20333。

至于如何解决这个问题,我不知道德尔福 RTL 中的另一个功能可以执行此任务。因此,我认为您需要执行以下操作之一:

  • 滚动自己的StrToFloat.
  • 预处理字符串,并在读取StrToFloat之前处理超出范围的指数。
  • 使用 C 运行时库中执行相同任务的函数之一。

最后,我很感激你问这个问题,因为我可以看到我自己的程序受到这个缺陷的影响,所以我现在可以修复它了!

更新:

您可能还有兴趣查看我在调查时发现的相关错误:RSP-20334。您可能会惊讶地发现,StrToFloat('߀')在使用 PUREPASCAL 版本的StrToFloat时,返回1936.0。诀窍是传递给StrToFloat的字符是非拉丁数字,在本例中为 U+07C0。

相关内容

最新更新