当前位置 : 主页 > 网络安全 > 测试自动化 >

性能 – 更快的sin()为x64

来源:互联网 收集:自由互联 发布时间:2021-06-22
主要问题 有人对x64有快速的sin()实现吗? 它不需要是纯粹的pascal. 说明 我有一个VCL应用程序,在某些情况下,当它为x64编译时运行速度慢很多. 它进行了大量的浮点3d计算,并且我已经跟踪
主要问题

有人对x64有快速的sin()实现吗?
它不需要是纯粹的pascal.

说明

我有一个VCL应用程序,在某些情况下,当它为x64编译时运行速度慢很多.

它进行了大量的浮点3d计算,并且我已经跟踪了这一事实,当输入值变大时,System.Sin()和System.Cos()在x64上要慢很多.

我通过创建一个简单的测试应用程序来计算它,它可以测量计算sin(x)所需的时间,x的值不同,差异很大:

call:     x64:     x86:
              Sin(1)   16 ms    20 ms
             Sin(10)   30 ms    20 ms
            Sin(100)   32 ms    20 ms
           Sin(1000)   34 ms    21 ms
          Sin(10000)   30 ms    21 ms
         Sin(100000)   30 ms    16 ms
        Sin(1000000)   35 ms    20 ms
       Sin(10000000)  581 ms    20 ms
      Sin(100000000) 1026 ms    21 ms
     Sin(1000000000) 1187 ms    22 ms
    Sin(10000000000) 1320 ms    21 ms
   Sin(100000000000) 1456 ms    20 ms
  Sin(1000000000000) 1581 ms    17 ms
 Sin(10000000000000) 1717 ms    22 ms
Sin(100000000000000) 1846 ms    23 ms
           Sin(1E15) 1981 ms    21 ms
           Sin(1E16) 2100 ms    21 ms
           Sin(1E17) 2240 ms    22 ms
           Sin(1E18) 2372 ms    18 ms
                etc    etc      etc

你在这里看到的是罪(1E5)的速度是罪的1倍(1E8).

如果您有兴趣,我已经创建了上面这样的表格:

{$APPTYPE CONSOLE}
program SinTest;

uses Diagnostics, Math, SysUtils;

var
  i : Integer;
  x : double;
  sw: TStopwatch;

begin
  x := 1;

  while X < 1E18 do
  begin
    sw    := TStopwatch.StartNew;
    for i := 1 to 500000 do
      System.Sin(x);

    // WriteLn(System.sin(x), #9,System.Sin(fmod(x,2*pi)));

    sw.Stop;

    WriteLn('    ', ('Sin(' + round(x).ToString + ')'):20, ' ', sw.ElapsedMilliseconds,' ms');

    x := x * 10;
  end;

  WriteLn('Press any key to continue');
  readln;
end.

笔记:

>关于更快的正弦函数,StackOverflow有一些问题,但它们都没有源代码可以移植到Delphi,如下所示:Fastest implementation of sine, cosine and square root in C++ (doesn’t need to be much accurate)
> x64的其余部分比32比特的运行速度快
>通过这样做,我发现了一些糟糕的解决方法:
SIN(闪存模块(X,2 * PI)).它提供了正确的结果,并且对于更大的数字它可以快速运行.对于较小的数字,它当然有点慢.

虽然在用户模式代码中可能会强烈反对这一点(并且在内核模式代码中完全被禁止),但如果您确实希望在x64代码中保留旧版x87行为,则可以编写如下函数:

function SinX87(x:double):double;
var
  d : double;
asm
  movsd qword ptr [rbp+8], xmm0
  fld qword ptr [rbp+8]
  fsin
  fstp qword ptr [rbp+8]
  movsd xmm0, qword ptr [rbp+8]
end;

这会增加一些开销,因为您必须将SSE寄存器中的值弹出到堆栈中,将其加载到x87单元中,执行计算,将值弹回到堆栈,然后将其加载回XMM0以获取功能结果.然而,罪恶计算相当沉重,所以这是一个相对较小的开销.如果你需要保留x87的xxx实现,我真的会这样做.

存在其他库,在x64代码中比Delphi的purepascal例程更有效地计算sin.我压倒性的偏好是将一组好的C例程导出到DLL中.此外,正如大卫所说,无论如何,使用具有可笑大量参数的trig函数并不是一件明智的事情.

网友评论