delphi – 如何在64位代码中实现高效的32位DivMod

我想使用一个专门在32位操作数上运行的DivMod函数. implementation in the RTL以16位变量返回值.它的声明是:
procedure DivMod(Dividend: Cardinal; Divisor: Word; var Result,Remainder: Word);

所以,我不能使用它,因为我的输入可能溢出返回值.

朴素的Pascal实现如下所示:

procedure DivMod(Dividend,Divisor: Cardinal; out Quotient,Remainder: Cardinal);
begin
  Quotient := Dividend div Divisor;
  Remainder := Dividend mod Divisor;
end;

这很好地工作,但执行两次分裂.由于我的代码的一部分调用函数,这是一个性能瓶颈,我只想执行一次除法.为此我从这个问题使用Serg的32位DivMod:Is there a DivMod that is *not* Limited to Words (<=65535)?

procedure DivMod(Dividend,Remainder: Cardinal);
asm
        PUSH EBX
        MOV  EBX,EDX
        XOR  EDX,EDX
        DIV  EBX
        MOV  [ECX],EAX
        MOV  EBX,Remainder
        MOV  [EBX],EDX
        POP  EBX
end;

这非常有效.

但现在我想要一个64位代码函数版本.请注意,我仍然希望对32位操作数进行操作,并返回32位值.

我应该使用64位汇编程序重新编写函数,还是使用运行的RTL的DivMod重载并返回64位值就足够了?

具体来说,我想知道在编写执行32位操作的64位代码时是否有性能优势.这有可能吗?或者我最终会用UInt64参数重新实现DivMod重载?如果值得实现一个定制的64位asm版本,我将如何去做,注意操作数和操作是32位.

我认为它看起来像这样,但我不是专家,可能有错误

procedure DivMod(Dividend,Remainder: Cardinal);
asm
        MOV   EAX,ECX   // move Dividend to EAX
        MOV   ECX,EDX   // move Divisor to ECX
        XOR   EDX,EDX   // zeroise EDX
        DIV   ECX       // divide EDX:EAX by ECX
        MOV   [R8],EAX  // save quotient
        MOV   [R9],EDX  // save remainder
end;

解决方法

对于总是除以10(每条评论)的特殊情况,您可以执行以下操作:
procedure DivMod10(num : Cardinal; var q,r : Cardinal); inline;
var
  rl : uInt64;
begin
  rl := UInt64(3435973837)*num;
  q := rl shr 35;
  r := num - q*10;
end;

算法根据分母而有所不同,但确定它的来源和幻数可以在libdivide中找到.这对于所有无符号32位整数都是准确的,并且比使用div快3倍(并提供余数) .

基准(优化):

t0 := GetTickCount;
  for I := 1 to 999999999 do begin
    DivMod10(i,q,r);
  end;
  ShowMessage(IntToStr(GetTickCount - t0));  // result :  1809

  t0 := GetTickCount;
  for I := 1 to 999999999 do begin
    q := i div 10;
  end;
  ShowMessage(IntToStr(GetTickCount - t0));  // result :  5336

测试:

for I := 1 to High(Cardinal) do begin
  DivMod10(i,r);
  if q <> (i div 10) then WriteLn(IntToStr(i));
  // no mismatch found
end;

相关文章

 从网上看到《Delphi API HOOK完全说明》这篇文章,基本上都...
  从网上看到《Delphi API HOOK完全说明》这篇文章,基本上...
ffmpeg 是一套强大的开源的多媒体库 一般都是用 c/c+&#x...
32位CPU所含有的寄存器有:4个数据寄存器(EAX、EBX、ECX和ED...
1 mov dst, src dst是目的操作数,src是源操作数,指令实现的...