我正在对UInt64值中的大整数进行一些繁重的工作,并且想知道Delphi是否具有整数平方根函数.现在我正在使用,Trunc(Sqrt(x*1.0))
但我想必须有一个更高效的方式,也许有一个内联汇编程序的片段?(Sqrt(x)
与x:UInt64
抛出D7无效类型编译器错误,因此*1.0
位.)
And*_*and 10
我离集会专家很远,所以这个答案只是我鬼混.
但是,这似乎有效:
function isqrt(const X: Extended): integer;
asm
fld X
fsqrt
fistp @Result
fwait
end;
Run Code Online (Sandbox Code Playgroud)
只要在调用之前将FPU控制字的舍入设置设置为"截断"即可isqrt
.最简单的方法可能是定义辅助函数
function SetupRoundModeForSqrti: word;
begin
result := Get8087CW;
Set8087CW(result or $600);
end;
Run Code Online (Sandbox Code Playgroud)
然后你就可以做到
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;
Run Code Online (Sandbox Code Playgroud)
这真的能提高性能吗?好吧,我测试了
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;
Run Code Online (Sandbox Code Playgroud)
并得到了结果
371802
371774.
Run Code Online (Sandbox Code Playgroud)
因此,它根本不值得.天真的方法trunc(sqrt(x))
更易于阅读和维护,具有出色的未来和向后兼容性,并且不易出错.