덧셈과는 다르게 뺄셈은 고려할게 두개나 더 있으며, 부호 (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
2010년 2월 14일 일요일
16장 - BCD 32비트 버전 2
피드 구독하기:
댓글 (Atom)
댓글 없음:
댓글 쓰기