主要问题
有没有人有一个适用于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
您在这里看到的是sin(1E5)
运行速度大约是sin(1E8)
的300倍。
如果您感兴趣,我是这样创建上述表格的:
{$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的源代码,就像这个:C++中最快的正弦、余弦和平方根实现(不需要太高的准确度)
x64的其余部分比32位的运行得更快。
我发现了一些垃圾解决方法,就是这样做:
Sin(FMod(x,2*pi))
。它可以提供正确的结果,并且对于较大的数字运行速度很快。当然,对于较小的数字,它会慢一些。
{$APPTYPE CONSOLE} var s1, s2: Single; begin s1 := 10000000.5; s2 := 10000000.0; Writeln(s1=s2); end.
这里有一个提示。输出不是FALSE
。 - David Heffernan