2010-03-07 3 views
4

는 DivMod 함수 선언 따라서* (* = 65535 이하) DivMod가 있습니까? 델파이

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

제수, 결과이고, 나머지는 65535 약간 심각한 제한보다 주장 할 수 없다. 왜 이런거야? 왜하지 delcaration는

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

귀하가 수락 한 답변은 제목에있는 질문에 대한 답변이 아닙니다. 제목을 편집하여 실제로 답을 원했던 내용과 더 가깝게 일치시킬 수 있습니다. –

+0

나는 그것을했다. –

답변

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 업데이트 :

Disassembly (또는 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 코드는 단지 약 걸립니다. div 및 mod 연산자 (적어도 i7 시스템에서)를 사용하는 순진 방식과 비교할 때 시간의 60 % (이상하지 않습니까? 델파이 컴파일러가 효율적인 코드를 작성해야합니까?) 왜 RTL은 DivMod의 16 비트 버전 만 제공한다고 생각합니까? –

+2

컴파일러가 할 수있는 일은 너무 많습니다. Serg은 (ab) 두 줄 모두 동일한 분할을 필요로한다는 사실과 동시에 몫과 나머지를 모두 얻을 수 있다는 사실을 사용합니다. 또한 공정한 비교는 메소드 서명의 차이로 인해 두 번째가 아닌 첫 번째 비교와 비교할 것을 요구합니다. 델파이가 작성한 19 개에 비해 손으로 쓴 ASM 코드는 8 개입니다. 추가 사업부를위한 3-4 가지 지침을 제거하면 8 가지 지침과 15 가지 지침이 적용됩니다. –

+1

남은 것은 설정/해제 코드가 다르기 때문에 대부분 다릅니다. D2010에서는 이러한 명령어 중 4 개가 실제로 코드에 추가됩니다 (EBP 조작 및 RET).이제 우리는 생성 된 코드에서 여분의 나누기를 제거하면 3 가지 장점이 있습니다. 그리고 제가 말할 수있는 한 그 차이는 Serg가 레지스터를 조금 더 교묘하게 선택하는 데서 오는 것입니다 (그 중 2 가지는 Serg not touching ESI). 그는 컴파일러보다 코드의 의도를 잘 알고 있기 때문에 그렇게 할 수 있습니다. 이는 사용자의 의도가 무엇인지 모르기 때문에 더 안전한 방식으로 작업을 수행합니다. –

관련 문제