StrToFloat无法在Delphi 64位中报告无效的浮点数

前端之家收集整理的这篇文章主要介绍了StrToFloat无法在Delphi 64位中报告无效的浮点数前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
以下代码尝试将值转换为超出双精度范围
StrToFloat('1e99999999')

使用Windows 32位编译器在Delphi 10.2r3中正确报告错误的浮点值,但是当使用Window 64位编译器进行编译时,它会以静默方式返回0(零)。

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

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

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

Delphi 10.2 update 3注意到了这个问题

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

解决方法

这是使用PUREPASCAL版本的StrToFloat的所有Delphi版本中存在的缺陷。这映射到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

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

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

最后,我很感谢您提出这个问题,因为我可以看到我自己的程序受到此缺陷的影响,因此我现在可以解决它!

更新:

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

原文链接:https://www.f2er.com/delphi/103233.html

猜你在找的Delphi相关文章