【问题标题】:Does Delphi have isqrt?德尔福有isqrt吗?
【发布时间】:2011-01-06 19:45:59
【问题描述】:

我正在对 UInt64 值中的大整数做一些繁重的工作,并且想知道 Delphi 是否有 integer square root 函数。 现在我正在使用Trunc(Sqrt(x*1.0)),但我想必须有一种更高效的方式,也许是使用内联汇编器的 sn-p? (Sqrt(x)with x:UInt64 在 D7 中引发无效类型编译器错误,因此出现 *1.0 位。)

【问题讨论】:

  • 是的,*1.0 已在更高版本中修复。不确定哪个更高版本,但它在 D2010 中肯定可以正常工作。

标签: delphi math


【解决方案1】:

我离装配专家还很远,所以这个答案只是我在胡闹。

但是,这似乎可行:

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)) 更易于阅读和维护,具有出色的未来和向后兼容性,并且不易出错。

【讨论】:

  • 啊,不用解释了。那就开心补偿吧。
  • @Worm:我们并不真正关心否决票,如果您解释其背后的原因以便每个人都可以学习,它会更有价值。毕竟,这就是 SO 的意义所在。
  • 嗯,你能骗我一个具有 UInt64 类型参数和结果的版本吗?
【解决方案2】:

我相信答案是否定的,它没有整数平方根函数,并且您的解决方案是合理的。

我有点惊讶于需要乘以 1.0 才能转换为浮点值。我认为这一定是一个 Delphi 错误,并且最近的版本肯定会如您所愿。

【讨论】:

  • 还有更多,我现在已经过了 2^32 标记,我得到了 EInvalidOp: Invalid floating point operation on my trick... 我想我要实现 old-skool algorhythm逐步计算iqrt...
  • @stijn 你要回到 uint64 吗?
  • Trunc 根据帮助执行...失败的是 Sqrt(x*1.0)
  • @Stijn 在最新版本的 Delphi 中一切正常。它在 Delphi 6 中对我来说很好用。您能否发布一个非常精简的代码版本作为您问题的更新。只是一个失败的例程。我相信它不会需要太多的整理。
【解决方案3】:

这是我最终使用的代码,基于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;

【讨论】:

    猜你喜欢
    • 2014-07-08
    • 1970-01-01
    • 1970-01-01
    • 2011-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-02
    • 2011-10-04
    • 2012-12-13
    相关资源
    最近更新 更多