时间:2011-01-06 19:45:59

标签: delphi math

3 个答案:

答案 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;