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找到
解决方法
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。