汇编语言直接定值表

分析:
一个字节需要用两个十六进制数码来表示,所以,子程序需要在屏幕上显示两个“ASCII字符。我们当然要用“0"、 “1”、“2”、“3”、"4”、“5”、“6”、“7”、“8”、“9”、"A”、"B’,"c’、“D"、"e’,"F这16个字符来显示十六进制数码。
我们可以将一个字节的高4位和低4位分开,分别用它们的值得到对应的数码字符。比如2Bh,可以得到高4位的值为2,低4位的值为11,那么如何用这两个数值得到对应的数码字符“2”和“B”呢?
最简单的办法就是一个一个地比较,如下:

如果数值为0,则显示“0";
如果数值为1,则显示“1";
.
如果数值为11,则显示“B":
.

我们可以看出,这样做,程序中要使用多条比较、转移指令。程序将比较长,混乱。
显然,我们希望能够在数值0-15和字符“0”-“F”之间找到一种映射关系。这样用O}ls间的任何数值,都可以通过这种映射关系直接得到“0”-“F”中对应的字符。
数值0~9和字符“0”-“9”之间的映射关系是很明显的,即:
教佰+30h=对应字件的ASCII值

0+30h= "0”的ASCII值
1+30h=“1”的ASCII值
2+30h= "2”的ASCII值

但是,10-15和“A”-"F”之间的映射关系是:

数值+37h=对应字符的ASCII值
10+37h= "A”的ASCII值
11+37h= "B”的ASCII值
12+37h= "C”的ASCII值

可见,我们可以利用数值和字符之间的这种原本存在的映射关系,通过高4位和低4位值得到对应的字符码。但是由于映射关系的不同,我们在程序中必须进行一些比较,对于大于9的数值,我们要用不同的计算方法。
这样做,虽然使程序得到了简化。但是,如果我们希望用更简捷的算法,就要考虑用同一种映射关系从数值得到字符码。所以,我们就不能利用0-9和“0”-“9”之间与
10-15和“A”-“F”之间原有的映射关系。
因为数值0-15和字符“0”-“F”之间没有一致的映射关系存在,所以,我们应该在它们之间建立新的映射关系。
具体的做法是,建立一张表,表中依次存储字符“0”-“F",我们可以通过数值0-15直接查找到对应的字符。
子程序如下。

;用al传送要显示的数据
showbyte: jmp short show
          table db '0123456789ABCDEF'    ;字符表

 show:  push bx
        push es

        mov ah,al
        shr ah,1
        shr ah,1
        shr ah,1
        shr ah,1          ;右移4位,ah中 得到高 4位的值
        and al,00001111b  ;al中为低4位的值

        mov bl,ah
        mov bh,0
        mov ah,table[bx]  ;用高4位的值作为相对于table的偏移,取得对应的字符

        mov bl,ah
        mov bh,0
        mov al,table[bx]   ;用低4位的值作为相对于table的偏移,取得对应的字符

        mov es:[160*12+40*2+2],al

        pop es
        pop bx

        ret

可以看出,在子程序中,我们在数值0-15和字符“0”-“F”之间建立的映射关系
为:以数值N为table表中的偏移,可以找到对应的字符。
利用表,在两个数据集合之间建立一种映射关系,使我们可以用查表的方法根据给出
的数据得到其在另一集合中的对应数据。这样做的目的一般来说有以下3个。

(t)为了算法的清晰和简洁;
(2)为了加快运算速度;
(3)为了使程序易于扩充。

在上面的子程序中,我们更多的是为了算法的清晰和简洁,而采用了查表的方法。下
面我们来看一下,为了加快运算速度而采用查表的方法的情况。

编写一个子程序,计算sin(x)} x E {00,300,600,900,1200,i500,180}并在屏幕中间显示计算结果。比如sin(30)的结果显示为“0.5 "。
我们可以利用麦克劳林公式来计算sin{x), x为角度,麦克劳林公式中需要代入弧度,则:

511遇见

可以看出,计算sin(x)需要进行多次乘法和除法。乘除是非常费时的运算,它们的执行时间大约是加法、比较等指令的5倍。如何才能够不做乘除而计算sin(x)呢?我们看一下需要计算的sin(x)的结果:

sin(0)=0
sin(30)=0.5
sin(60)=0.866
sin(90)=1
sin(120)=0.866
sin(150)=0.5
sin(180)=0

我们可以看出,其实用不着计算,计算的sin(x)的结果都存储到一张表中;可以占用一些内存空间来换取运算的速度。将所要然后用角度值来查表,找到对应的sin(x)的值。
用ax向子程序传递角度,程序如下:

assume cs:code

code segment
	start:mov al, 30
		  mov ah, 0
		  
		  call showSin
		  mov ax, 4c00h
		  int 21h
		
  showSin:jmp short show
	table		dw arg0, arg30, arg60, arg90, arg120, arg150, arg180	;字符串偏移地址
	arg0		db '0', 0
	arg30		db '0.5', 0
	arg60		db '0.866', 0
	arg90		db '1', 0
	arg120		db '0.866', 0
	arg150		db '0.5', 0
	arg180		db '0', 0
  
	 show:push bx
		  push es
		  push si
		  
		  mov bx, 0b800h
		  mov es, bx
	;以下用角度/30作为相对于table的偏移,取得对应的字符串的偏移地址,放在bx中
		  mov ah, 0
		  mov bl, 30
		  div bl
		  mov bl, al
		  mov bh, 0
		  add bx, bx
		  mov bx, table[bx]
	;以下显示sin(x)对应的字符串
		  mov si, 160*12+40*2
	shows:mov ah, cs:[bx]
		  cmp ah, 0
		  je showret
		  mov es:[si], ah
		  inc bx
		  add si, 2
		  jmp short shows
	 
  showret:pop si
		  pop es
		  pop bx
		  ret
		  
code ends
end start 

在上面的子程序中,我们在角度值x和表示sin(x)的字符串集合table之间建立的映射关系为:以角度值/30为table表中的偏移,可以找到对应的字符串的首地址。
编程的时候要注意程序的容错性,即对于错误的输入要有处理能力。在上面的子程序中,我们还应该再加上对提供的角度值是否超范围的检测。如果提供的角度值不在合法的集合中,程序将定位不到正确的字符串,出现错误。对于角度值的检测,请读者自行完成。
上面的两个子程序中,我们将通过给出的数据进行计算或比较而得到结果的问题,转化为用给出的数据作为查表的依据,通过查表得到结果的问题。具体的查表方法,是用查表的依据数据,直接计算出所要查找的元素在表中的位置。像这种可以通过依据数据,直接计算出所要找的元素的位置的表,我们称其为直接定址表。


发布日期:

所属分类: 编程 标签:


没有相关文章!