2010년 2월 14일 일요일

16장 - BCD 32비트 버전 2


덧셈과는 다르게 뺄셈은 고려할게 두개나 더 있으며, 부호 (sign)와 절대치 (abs)이다. 뺄셈을 하기 전에 이를 먼저 체크하고 이어서 뺄셈을 해줘야
정확한 답을 얻게된다. 몇가지 뺄셈의 예를 들어보자.

예1. 5 - 2 = 3     ; (큰 양수) A - (작은 양수) B
예2. 5 - 7 = -2    ; (작은 양수) A - (큰 양수) B

예3. -5 - 3 = -8   ; (큰 음수) A - (작은 양수) B
예4. -5 - 7 = -12  ; (작은 음수) A - (큰 음수) B

보다시피 절대치의 크고 작음에 따라 부호도 덩달아 변한다. 어셈블리 코드로 플랙이 어떻게 변하는지 살펴보자.

  mov al, 5
  sub al, 2         ; al = 03, CF = 0, SF = 0

  mov bl, 5
  sub bl, 7         ; bl = FE, CF = 1, SF = 1

  mov cl, -5
  sub cl, 3         ; cl = F8, CF = 0, SF = 1

  mov dl, -5
  sub dl, 7         ; dl = F4, CF = 0, SF = 1

  mov al, -5
  sub al, -2        ; al = FD, CF = 1, SF = 1

  mov al, -5
  sub al, -7        ; al = 02, CF = 0, SF = 1

수학과는 다르게 여기서 부호를 결정하는 SF 플랙은 절대치의 영향보다는 단지 결과의 음/양을 결정하는 용도밖에 안됨을 알 수 있다. 우리는 BCD
뺄셈을 할 것이므로 AAS 명령을 다시 살펴볼 필요가 있다.

IF ((AL and 0Fh) > 9) or (AF = 1)
then
  AL <- AL - 6
  AH <- AH - 1
  AF <- 1
  CF <- 1
else
  CF <- 0
  AF <- 0
FI
AL <- AL and 0Fh

이 유사코드를 보면, AX에 두자리 BCD를 정해주고 연산하라고 암시를 주고 있다고할 수 있다. 다음 예를 생각해보자.

  mov al, 07h
  sub al, 09h
  aas

이 경우 한자리에서 한자리를 뺏지만, 00FEh라는 바이트 레벨 음수값이 AAS를 거치는 순간 FF08로 변한다. 즉, 00FF 에서 AX가 00이라고 할 경우,
FF로 1을 빼주고, AL은 E - 6 = 8 이 된 것에서 상위 니블 F를 마스킹하므로 이런 결과가 나왔다. 반면,

  mov al, 09h
  sub al, 07h
  aas

라고 하면 AX는 0002h로 변하지 않는다. 그러므로 우리는 다음처럼 규칙을 정해야 한다. X, Y 두 수를 뺄셈하여 AAS로 unpacked BCD 변환을 할 경우,
절대치가 큰 수일 경우 서로 바꿔서 빼야하고, 뺀 수에 '-' 기호를 암시적으로 붙여줘야한다. 절대치가 작은 수를 뺄 경우는 문제되지 않는다. 이제,
우리는 소수점 이하 자릿수도 있는 복정밀 BCD 뺄셈을 하려한다. 예로, "1234.5678" - "98765.43219"을 뺀다고 하자. 이는 빼려는 수 (numerator)가
빼야할 수 (denominator) 보다 절대치가 적으므로 음수가 되어야하고, 소숫점이하 자릿수가 확장되어야할 필요가 있다. 윈도우즈 계산기로 계산해본
결과 다음과 같다:

     1234.5678
-   98765.43219
------------------
= - 97530.86439

이 계산을 어떻게 할 것인가 ? 먼저, 소숫점 (decimal point)을 찾아내어, 소숫점 왼쪽을 정수 부분 (integer part), 오른쪽을 실수 부분 (fractional
part)로 구분한 후, 정수 부분은 절대치를 구해서 어느쪽에서 어느쪽을 뺄 것인지를 결정하고, 실수 부분은 소숫점 이하 자리를 몇개로 정해줄 것인지를
정해야한다. 우리의 예에서는 정수 부분은 5자리이며, 실수 부분은 6자리이고, 절대치는 denominator가 크므로 음수가 되어야한다. 먼저 두 수의
정수 부분과 소수 부분만 따로 구해내는 코드를 작성하자.

;==============================
; 16bits unpacked BCD integral part / factional part
;
.model small
.stack 100h

.data
  src1 db "1234.56"
  src2 db "123456.789"
  size1 dw sizeof src1
  size2 dw sizeof src2
  result db 10 dup (30h)
  intsrc1 db ?
  fracsrc1 db ?
  intsrc2 db ?
  fracsrc2 db ?
 
.code
start:

  mov ax, @data
  mov ds, ax
 
  lea si, src1
  lea di, src2

  mov cx, size1
  mov dx, size2
 
  xor ax, ax
  xor bx, bx
 
  mov bl, intsrc1             ; src1의 정수 카운터 로드
 
L1:                           ; src1의 소숫점이 어딘지 판단한다
  mov al, [si]
  cmp al, '.'
  je L2
  inc bl
  inc si
  jnz L1

L2:
  mov intsrc1, bl             ; src1의 정수 부분의 자릿수 저장
  mov bh, cl
  sub bh, bl
  sub bh, 1                   ; 소숫점은 자릿수에서 제외
  mov fracsrc1, bh            ; src1의 소수 부분의 자릿수 저장
 
 
  mov bl, intsrc2             ; src2의 정수 카운터 로드
 
L3:                           ; src2의 소숫점 판단
  mov al, [di]
  cmp al, '.'
  je L4
  inc bl
  inc di
  jnz L3
 
L4: 
  mov intsrc2, bl             ; src2의 정수 부분 자릿수 저장
  mov bh, dl
  sub bh, bl
  sub bh, 1
  mov fracsrc2, bh            ; src2의 소수 부분 자릿수 저장
 
@@:
  mov ah, 01h                 ; 지연
  int 21h

  or al, al                       
  jz Last

Last:
;============================== 

end start

댓글 없음:

댓글 쓰기

블로그 보관함