2010-03-07 60 views
4

在Delphi,所述DivMod函數的聲明是是否有DivMod是*不*字(<= 65535)?

procedure DivMod(Dividend: Cardinal; Divisor: Word; 
    var Result, Remainder: Word); 

因此,除數,結果,和餘數不能磨碎機大於65535,一個相當嚴重的限制。爲什麼是這樣?爲什麼不能放置

procedure DivMod(Dividend: Cardinal; Divisor: Cardinal; 
    var Result, Remainder: Cardinal); 

該過程是使用匯編實現的,因此可能非常快。代碼

PUSH EBX 
    MOV  EBX,EDX 
    MOV  EDX,EAX 
    SHR  EDX,16 
    DIV  BX 
    MOV  EBX,Remainder 
    MOV  [ECX],AX 
    MOV  [EBX],DX 
    POP  EBX 

難以適應紅雀嗎?天真的嘗試要慢多少?

procedure DivModInt(const Dividend: integer; const Divisor: integer; out result: integer; out remainder: integer); 
begin 
    result := Dividend div Divisor; 
    remainder := Dividend mod Divisor; 
end; 

那不是(?)限於16位整數嗎?

+0

您接受的答案不能回答標題中的問題。也許你可以編輯標題,使它更貼近你真正想要的答案。 – 2010-03-08 09:10:15

+0

我已經完成了。 – 2010-03-08 13:11:39

回答

13

這樣的程序是可能的。我沒有測試的代碼足夠了,但我認爲這是確定:

procedure DivMod32(Dividend, Divisor: Cardinal; var Quotient, 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; 

更新時間:

更高效:

function DivMod32(Dividend, Divisor: Cardinal; var Remainder: Cardinal): Cardinal; 
asm 
     PUSH EBX 
     MOV EBX,EDX 
     XOR EDX,EDX 
     DIV EBX 
     MOV [ECX],EDX 
     POP EBX 
end; 

更新2:

您可以在反彙編(或CPU)窗口中看到由Delphi編譯器生成的彙編代碼。例如,該過程

procedure DivMod32(const Dividend: Cardinal; const Divisor: Cardinal; 
        out result: Cardinal; out remainder: Cardinal); 
begin 
    result := Dividend div Divisor; 
    remainder := Dividend mod Divisor; 
end; 

生成代碼

Unit1.pas.28: begin 
0046CC94 55    push ebp 
0046CC95 8BEC    mov ebp,esp 
0046CC97 53    push ebx 
0046CC98 56    push esi 
0046CC99 8BF2    mov esi,edx 
0046CC9B 8BD8    mov ebx,eax 
Unit1.pas.29: result := Dividend div Divisor; 
0046CC9D 8BC3    mov eax,ebx 
0046CC9F 33D2    xor edx,edx 
0046CCA1 F7F6    div esi 
0046CCA3 8901    mov [ecx],eax 
Unit1.pas.30: remainder := Dividend mod Divisor; 
0046CCA5 8BC3    mov eax,ebx 
0046CCA7 33D2    xor edx,edx 
0046CCA9 F7F6    div esi 
0046CCAB 8B4508   mov eax,[ebp+$08] 
0046CCAE 8910    mov [eax],edx 
Unit1.pas.31: end; 
0046CCB0 5E    pop esi 
0046CCB1 5B    pop ebx 
0046CCB2 5D    pop ebp 
0046CCB3 C20400   ret $0004 

該代碼是線性的(不包含跳躍)和現代處理器(長指令流水線)是在執行線性碼非常有效的。所以雖然我的DivMode32的實現時間縮短了大約3倍,但60%是合理的估計。

+0

非常感謝。您的ASM代碼只需要約。 60%的時間與使用div和mod操作符(至少在我的i7系統上)的天真方法相比。 (這不奇怪嗎?Delphi編譯器不應該創建高效代碼嗎?) 爲什麼你認爲RTL只提供16位版本的DivMod? – 2010-03-07 23:16:41

+2

只有這麼多的編譯器可以期望做到。 Serg是(ab)使用這兩條線需要相同的分割這一事實,並且他可以同時得到商和餘數。還要注意,由於方法簽名的不同,公平比較要求您將其與第一個比較,而不是第二個比較。這是手寫ASM代碼中的8條指令,而德爾福創建的19條指令。除去額外分區的3-4個指令,並且你減少到8個與15個指令。 – 2010-03-08 00:28:00

+1

由於不同的設置/拆卸代碼,你留下的內容大多不相同。在D2010中,這些指令中的4條實際上被添加到他的代碼中(EBP操作和RET)。現在我們只有3個指令的優勢,如果你從生成的代碼中刪除額外的分割 - 並且據我所知,差異來自於Serg選擇他的寄存器更巧妙一些(其中2個被Serg切割而沒有觸及ESI)。他可以這樣做,因爲他比編譯器更瞭解代碼的意圖 - 它可能以更安全的方式執行,因爲它不知道你的意圖是什麼。 – 2010-03-08 00:42:03