压缩BCD码简介
压缩十进制数的每个字节存放两个十进制数字,每个数字用 4 位表示。
bcd1 QWORD 2345673928737285h ;十进制数 2345673928737285
bcd2 DWORD 12345678h ;十进制数 12345678
bcd3 DWORD 08723654h ;十进制数 8723654
bcd4 WORD 9345h ;十进制数 9345
bcd5 WORD 0237h ;十进制数 237
bcd6 BYTE 34h ;十进制数 34
虽然声明的是16进制数,但是在压缩BCD码的的标准下,16进制的0~9与10进制的0~9刚好是相同的。压缩十进制存储至少有两个优势:1) 数据几乎可以包含任何个数的有效数字。这使得以很高的精度执行计算成为可能。2) 实现压缩十进制数与 ASCII 码之间的相互转换相对简单。
压缩BCD码有对应的加减法指令,但目前还没有乘除法指令,所以当使用乘除法时两个操作数必须是非压缩BCD码。
DAA指令
DAA (Decimal Adjust after Addition)加法后的十进制调整,32 位模式下,先用ADD 或 ADC 指令在 AL 中生成二进制和数,再用DAA指令将和数转换为压缩十进制格式。比如,下述指令执行压缩十进制数 35 加 48。如果视为16进制数相加,那么35h+48h=7Dh,但是通过DAA指令转化后结果变成83(35+48=83)。
.386
.model flat, stdcall
.stack 4096
ExitProcess proto, dwExitcode:dword
Include Irvine32.inc
.data
.code
main proc
nop
mov al, 35h
add al, 48h
daa ;AL=83h
invoke ExitProcess, 0
main endp
end main
下面的程序执行两个 16 位压缩十进制整数加法,并将和数保存在一个压缩双字中。
.386
.model flat, stdcall
.stack 4096
ExitProcess proto, dwExitcode:dword
Include Irvine32.inc
.data
num1 WORD 4536h
num2 WORD 7207h
sum DWORD ?
.code
main proc
clc
mov esi, 0
mov ecx, type num1
L1:
mov al, byte ptr num1[esi]
adc al, byte ptr num2[esi] ;此处使用adc而不用add,是因为两数相加有可能进位。
daa
mov byte ptr sum[esi], al
inc esi
loop L1
adc byte ptr sum[esi], 0 ;此处再次重复,因为最后一位相加后有可能进位标志位里有内容。
invoke ExitProcess, 0
main endp
end main
DAS指令
Decimal Adjust AL after Subtraction,减法后的十进制调整。先完成SUB或SBB指令在AL中生成二进制结果,然后再用DAS指令将其转换为压缩BCD码。
具体调整规则如下:
- 如果 AL 的低四位大于 9,或 AF=1,那么,AL=AL-06H,并置 AF=1;
- 如果 AL 的高四位大于 9,或 CF=1,那么,AL=AL-60H,并置 CF=1;
- 如果以上两点都不成立,则清除标志位 AF 和 CF。
比如,下面的语句计算压缩十进制数 85 减 48,并调整结果:
.386
.model flat, stdcall
.stack 4096
ExitProcess proto, dwExitcode:dword
Include Irvine32.inc
.data
.code
main proc
mov bl,48h
mov al,83h
sub al,bl
das
invoke ExitProcess, 0
main endp
end main