2016-09-08 5 views
0

현재 프로세스에서 .386을 사용하는 것으로 제한됩니다. intel x86을 사용하면 어떻게 부서의 소수점을 구할 수 있습니까? 12.81x86 어셈블리 - 소수점 이하 자릿수를 가져 오는 idiv

여기에 내 현재 코드입니다 : 내가 처음 100 AX를 곱하여 시도했습니다

mov AX, Dividend 
cwd 
idiv Divisor 

outputW AX ;Outputs Quotient (whole number) 
outputW DX ;Outputs Remainder 

는하지만 여전히 나를 위해 작동하지 않았다 기본적으로 나는 백 장소 등에 출력을 할 수 있습니다. 저는 현재 변수를 DividendDivisor으로 제한하고 있습니다. 나는 cwde 명령으로 cwd을 바꾸려고했지만 저를 위해 작동하지 않았습니다.

도움이 될 것입니다.

감사

+3

100을 곱하면 나머지를 가지고 원래하여 분할 긍정적 제수. 반올림을 위해 조정해야합니다. –

+0

32 비트 환경에있는 경우 _AX_ 대신 _EAX_ 및 _DX_ 대신 _EDX_와 같은 32 비트 레지스터를 사용할 수 있습니다. –

+0

@MichaelPetch 감사합니다. 이제 EA 변수를 EAX로 옮겨서 전체 EAX를 사용할 수있는 방법은 무엇입니까? 나는 그것을하는 방법에 대해 혼란스러워했다. – LearningProcess

답변

2

당신은 다시 소수점 이하 두 자리를 얻기 위해 100에 의해 분할, 분할을 수행하기 전에 100에 의해 배당을 곱 라운딩 조정할 수 있습니다. 초기 코드는 16 비트이기 때문에, 여기에 16 비트 솔루션은 처음이다 :

;; Perform the initial division (100 * Dividend/Divisor) 
    MOVSX EAX, Dividend ; Sign-extend the Dividend into EAX 
    IMUL OneHundred  ; EDX:EAX = EAX * 100 
    MOVSX ECX, Divisor ; Sign-extend the Divisor into ECX 
    IDIV ECX   ; EDX:EAX/Divisor... EAX=Quotient, EDX=Remainder 

    ;; Handle the remainder 
    SHL EDX, 1   ; EDX now equals the remainder times two 
    CMP EDX, ECX  ; Compare Remainder*2 to the Divisor 
    JL l1    ; If Remainder*2 is <, we round down (nothing changes) 
    INC EAX    ; If Remainder*2 is >=, we round up (increment the quotient) 
l1: 

    ;; Divide by 100 again to get the final result 
    CDQ     ; Sign-extend EAX to EDX:EAX 
    IDIV OneHundred  ; EDX:EAX/100... EAX=Quotient, EDX=Remainder 
    MOV IntegerPart, EAX ; Now EAX is the integer part 
    MOV DecimalPart EDX ; And EDX is the fractional part 

OneHundred DD 100 
: 32 비트 솔루션을 적용 할 경우

;; Perform the initial division (100 * Dividend/Divisor) 
    MOV AX, Dividend ; Load the Dividend into AX 
    IMUL OneHundred  ; DX:AX = AX * 100 
    IDIV Divisor  ; DX:AX/Divisor... AX=Quotient, DX=Remainder 

    ;; Handle the remainder 
    SHL DX, 1   ; DX now equals the remainder times two 
    CMP DX, Divisor  ; Compare Remainder*2 to the Divisor 
    JL l1    ; If Remainder*2 is <, we round down (nothing changes) 
    INC AX    ; If Remainder*2 is >=, we round up (increment the quotient) 
l1: 

    ;; Divide by 100 again to get the final result 
    CWD     ; Sign-extend AX to DX:AX 
    IDIV OneHundred  ; DX:AX/100... AX=Quotient, DX=Remainder 
    MOV IntegerPart, AX ; Now AX is the integer part 
    MOV DecimalPart DX ; And DX is the fractional part 

OneHundred DW 100 

또는, 대신 32 비트 정수를 사용할 수 있습니다


참고 : 32 비트 코드는 큰 지수로 Divide Errors을 생성하지 않으므로 바람직합니다. 16 비트의 경우 Dividend=32767Divisor=1를 고려

  • 제 승산 않는다 : DX:AX = 32767*100 = 3276700
  • 제 부문 않는다 : DX:AX/1 = 3276700/1 = 3276700을 (제로 나머지) 그러나 3276700AX에 맞게 너무 커서 (그것을 가 32767보다 큰 경우) 나누기 오류가 생성됩니다.

3276700이 EAX에 들어갈 수 있기 때문에 32 비트에서는 발생하지 않습니다.

또 다른 메모를 (물론, 0으로 나누는 것은 여전히 ​​두 경우 모두에서 오류가 발생 것) :이 코드는 초기 부문의 결과를 가정하는 것은

+0

10 진수를 포함하여 콘솔에 출력하는 방법은 무엇입니까? 나는 패딩 된 0 때문에 많은 공간을 얻고있다. 'OneHundred DD 100'은 무엇을 의미합니까? 또한 이것을 부호있는 숫자로 변경할 수 있습니까? 나는 당신이 처음 부분의 결과가 긍정적이어야한다는 것을 언급 한 곳을 보았습니다. – LearningProcess

+1

32 비트 버전에서는 OneHundred의 필요성을 피하면서'imul eax, eax, 100' /'cdq'를 선호합니다. (또한 원하는 경우 eax 이외의 레지스터에 부호 확장 배당을 유지할 수 있습니다.) 물론 두 번째 idiv의 피연산자로 100을 사용해야합니다. 'mov ecx, 100' /'idiv ecx'는 컴파일러가 방출하는 것과 비슷합니다 ('-Os'로; 그렇지 않으면 모듈러 인버스와 약간의 시프 팅에 의해 상수에 의한 나눗셈을 곱하면됩니다). –

관련 문제