Delphi Tokyo 64位会将非正规数刷新为零? [英] Delphi Tokyo 64-bit flushes denormal numbers to zero?

查看:76
本文介绍了Delphi Tokyo 64位会将非正规数刷新为零?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在仔细查看system.math的源代码时,我发现
64位版本的Delphi Tokyo 10.2.3将不规范的IEEE-Doubles刷新为零,从随后的程序可以看出;

During a short look at the source code of system.math, I discovered that the 64-bit version Delphi Tokyo 10.2.3 flushes denormal IEEE-Doubles to zero, as can be seen from then following program;

{$apptype console}
uses
  system.sysutils, system.math;
var
  x: double;
const
  twopm1030 : UInt64 = $0000100000000000; {2^(-1030)}
begin
  x := PDouble(@twopm1030)^;
  writeln(x);
  x := ldexp(1,-515);
  writeln(x*x);
  x := ldexp(1,-1030);
  writeln(x);
end.

对于32位,输出是预期的

For 32-bit the output is as expected

8.69169475979376E-0311
8.69169475979376E-0311
8.69169475979376E-0311

但使用64位,我会得到

but with 64-bit I get

 8.69169475979375E-0311
 0.00000000000000E+0000
 0.00000000000000E+0000

所以基本上东京可以处理64中的反常数位模式下,常数可以正确写入,但是从算术运算甚至使用ldexp时,异常结果都将刷新为零。

So basically Tokyo can handle denormal numbers in 64-bit mode, the constant is written correctly, but from arithmetic operations or even with ldexp a denormal result is flushed to zero.

可以在其他系统上确认此观察结果吗?如果是,在哪里记录? (我能找到的有关零冲洗的唯一信息是,
当存储在Real48中时,反常数变为零)。

Can this observation be confirmed on other systems? If yes, where it is documented? (The only info I could find about zero-flushing is, that Denormals become zero when stored in a Real48).

更新::我知道对于两者 32位和64位都使用单个重载。对于32位,使用x87 FPU,并且对于所有精度(单精度,双精度,扩展精度),ASM代码实际上是相同的。 FPU始终返回一个80位扩展名,该扩展名存储在double中,不会过早截断。 64位代码在存储之前进行精度调整。
同时,我提交了一个问题报告( https://quality.embarcadero.com/browse/ RSP-20925 ),重点放在32位或64位结果不一致的地方。

Update: I know that for both 32- and 64-bit the single overload is used. For 32-bit the x87 FPU is used and the ASM code is virtually identical for all precisions (single, double, extended). The FPU always returns a 80-bit extended which is stored in a double without premature truncation. The 64-bit code does precision adjustment before storing. Meanwhile I filed an issue report (https://quality.embarcadero.com/browse/RSP-20925), with the focus on the inconsistent results for 32- or 64-bit.

推荐答案

更新

编译器对待重载选择的方式只有一个区别。

@Graymatter发现,称为 Single LdExp 重载是32位和64位编译器。唯一的区别是代码库,其中32位编译器使用asm代码,而64位编译器具有purepascal实现。

As @Graymatter found out, the LdExp overload called is the Single type for both the 32-bit and the 64-bit compiler. The only difference is the codebase, where the 32-bit compiler is using asm code, while the 64-bit compiler has a purepascal implementation.

要修复代码以使用正确的重载,显式定义 LdExp()第一个参数的类型,如下所示(64位):

To fix the code to use the correct overload, explicitly define the type for the LdExp() first argument like this it works (64-bit):

program Project116;

{$APPTYPE CONSOLE}
uses
  system.sysutils, system.math;
var
  x: double;
const
  twopm1030 : UInt64 = $0000100000000000; {2^(-1030)}
begin
  x := PDouble(@twopm1030)^;
  writeln(x);
  x := ldexp(Double(1),-515);
  writeln(x*x);
  x := ldexp(Double(1),-1030);
  writeln(x);
  ReadLn;
end. 

输出:

 8.69169475979375E-0311
 8.69169475979375E-0311
 8.69169475979375E-0311






我想说,此行为应报告为RTL错误,,因为在您的案例中选择的重载函数是 Single 类型。结果类型为 Double ,编译器肯定会进行相应调整。
,因为32位和64位编译器应产生相同的结果。结果。


I would say that this behaviour should be reported as a RTL bug, since the overloaded function selected in your case is the Single type. The resulting type is a Double and the compiler should definitely adapt accordingly. since the 32-bit and the 64-bit compiler should produce the same result.

注意 Double(1)浮点类型的类型转换。有关prevoius版本的解决方案,请参见什么是Delphi的第一个版本,该版本允许进行double(10)之类的类型转换

Note, the Double(1) typecast for floating point types, was introduced in Delphi 10.2 Tokyo. For solutions in prevoius versions, see What is first version of Delphi which allows typecasts like double(10).

这篇关于Delphi Tokyo 64位会将非正规数刷新为零?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆