答案 0 :(得分:10)
我离集会专家很远,所以这个答案只是我鬼混。
但是,这似乎有效:
function isqrt(const X: Extended): integer;
asm
fld X
fsqrt
fistp @Result
fwait
end;
只要在调用isqrt
之前将FPU控制字的舍入设置设置为“截断”即可。最简单的方法可能是定义辅助函数
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))
更容易阅读和维护,具有出色的未来和向后兼容性,并且不容易出错。
答案 1 :(得分:1)
答案 2 :(得分:1)
这是我最终使用的代码,基于one of the algorhythms listed on wikipedia
type
baseint=UInt64;//or cardinal for the 32-bit version
function isqrt(x:baseint):baseint;
var
p,q:baseint;
begin
//get highest power of four
p:=0;
q:=4;
while (q<>0) and (q<=x) do
begin
p:=q;
q:=q shl 2;
end;
//
q:=0;
while p<>0 do
begin
if x>=p+q then
begin
dec(x,p);
dec(x,q);
q:=(q shr 1)+p;
end
else
q:=q shr 1;
p:=p shr 2;
end;
Result:=q;
end;