Главный вопросFaster грех() для x64
ли кто-нибудь есть быстрый грех() реализацию для x64? Не обязательно быть чистым паскалем.
Объяснение
У меня есть приложение VCL, что в некоторых ситуациях работает намного медленнее, когда он скомпилирован для x64.
Он выполняет множество вычислений 3d с плавающей запятой, и я проследил это до того, что System.Sin() и System.Cos() намного медленнее на x64, когда входные значения становятся большими.
Я засек, создав простое приложение тест, который измеряет, сколько времени требуется, чтобы вычислить sin(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)
работает примерно в 300 раз быстрее, чем sin(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 бит nterpart
Я нашел немного дрянной обходной путь, сделав это:
Sin(FMod(x,2*pi))
. Он дает правильные результаты, и он работает быстро для больших чисел. Для меньших чисел это, конечно, немного медленнее.
Предположительно, вас не волнует точность или вы не будете называть триггерные функции такими большими значениями. Неужели вы понимаете, что округление означает, что триггерные функции бессмысленны для таких входных значений? Или точность просто не важна для вас? –
Итак, посмотрите, можете ли вы угадать вывод этой программы: '{$ APPTYPE CONSOLE} var s1, s2: Single; начало s1: = 10000000.5; s2: = 10000000,0; Writeln (s1 = s2); конец. 'Вот ключ. Выход не является FALSE. –
Кажется, что MSVC может сделать это быстрее, и мне было бы интересно узнать, как, потому что я уверен, что он делает это быстрее для входных значений, которые тоже разумны. Но для ваших больших входных значений вы тратите свое время даже на вызов этих триггерных функций, как показывает мой предыдущий комментарий. –