Я очень далек от специалиста по сборке, поэтому этот ответ просто дурачит меня.
Однако, похоже, это работает:
function isqrt(const X: Extended): integer;
asm
fld X
fsqrt
fistp @Result
fwait
end;
до тех пор, пока вы установите для параметра округления слова управления FPU значение "усечь" до вызова isqrt
Самым простым способом может быть определение вспомогательной функции
function SetupRoundModeForSqrti: word;
begin
result := Get8087CW;
Set8087CW(result or $600);
end;
и тогда вы можете сделать
procedure TForm1.FormCreate(Sender: TObject);
var
oldCW: word;
begin
oldCW := SetupRoundModeForSqrti; // setup CW
// Compute a few million integer square roots using isqrt here
Set8087CW(oldCW); // restore CW
end;
Тест
Это действительно улучшает производительность? Ну я тестировал
procedure TForm1.FormCreate(Sender: TObject);
var
oldCW: word;
p1, p2: Int64;
i: Integer;
s1, s2: string;
const
N = 10000000;
begin
oldCW := SetupRoundModeForSqrti;
QueryPerformanceCounter(p1);
for i := 0 to N do
Tag := isqrt(i);
QueryPerformanceCounter(p2);
s1 := inttostr(p2-p1);
QueryPerformanceCounter(p1);
for i := 0 to N do
Tag := trunc(Sqrt(i));
QueryPerformanceCounter(p2);
s2 := inttostr(p2-p1);
Set8087CW(oldCW);
ShowMessage(s1 + #13#10 + s2);
end;
и получил результат
371802
371774.
Следовательно, это просто не стоит. Наивный подход trunc(sqrt(x))
гораздо легче читать и поддерживать, он имеет превосходную будущую и обратную совместимость и менее подвержен ошибкам.