使用8086汇编,输出99乘法表
程序运行截图如下:
要用汇编输出乘法表,实现思路有以下几点:
1.显示出等式:可以观察到乘法表的有9行,第1行有9列,第2行有8列,第3行有7列...而且每行的等式的第一个乘数都是该行所有的列数,等式的第二个乘数是该行所有的列数递减1(为第一个等式的情况下为列数)。如第一行有9列,等式的第1个乘数都为9,第1个等式的第2个乘数为列数9,第2个等式的第2个乘数为列数9-1=8,第3个等式的第2个乘数为列数9-1-1=7。
由这些特点可以得出用两层循环,并利用汇编loop指令的特点:每次到执行loop指令的时候,cx减一。可设置一个外层循环计数为9,内层循环计数随外层计数改变而改变,如第一次循环:外层计数等于9,内层计数等于9,循环9次打印出9个等式,等式第一个乘数都为9,等式第二个乘数从9开始递减;第二次循环:外层计数等于8,内层计数等于8,打印出8个等式,等式第一个乘数都为8,等式第二个乘数从8开始递减...
2.计算等式:计算等式的值,我们需要存下两个乘数,再用乘法指令进行计算
3.显示计算出来的值:由于99乘法表计算出来的值为1到81。汇编中用显示数值要进行相应的转换,0-9之间的数转换比较方便,用数值加上30h转为ASCII码输出。对于不只有个位的数值,可以用除10法进行转换,把各个位上的数转换出来,再套用显示0-9的方法进行显示,如81,转为8、1,分别输出两个字符8和1,即可在屏幕上得到81的效果。(除10法在前一篇博客中有比较详细的介绍)
个人在实现的时候有一些问题,详见注释,请高手指点,谢谢
代码如下(是可以跑通的...)
DATAS SEGMENT CRLF db 13,10,'$' number dw ?,?,?,? ;存放乘数和被乘数 buf db ?,?,?,? ;缓存转换出来的数字 DATAS ENDS CODES SEGMENT ASSUME CS:CODES,DS:DATAS START: MOV AX,DATAS MOV DS,AX mov cx,9 ;外层循环9次 s1: mov [number],cx ;存放乘数 push cx ;保存外层计数 push cx ;乘数进栈 s2: ;内层循环,循环次数由外层循环来决定 ;显示乘数 mov dx,[number] add dx,30h ;转换到ASCII mov ah,2 int 21h ;显示x号 mov dl,78h mov ah,2 int 21h ;显示第二个乘数 mov [number+1],cx push cx ;第二个乘数进栈 mov dx,cx add dx,30h mov ah,2 int 21h ;显示=号 mov dl,3dh mov ah,2 int 21h ;计算两数相乘的结果,并显示 pop dx ;取出第二个乘数 pop ax ;取出第一个乘数 push ax ;第一个乘数再次进栈,在下次内层循环中推出再次使用 ;想直接用内存单元里面放的数据来相乘,但是结果不对 ;所以最后用栈存放乘数再取出解决了问题 ;调试发现第二个乘数[number+1]中的值是对的,但是[number]中的值不对 ;很疑惑的是上面打印[number]的值显示结果正确 ;那为什么在下面的指令中使用值就不对了呢? ;mov dx,[number] ;mov ax,[number+1] mul dx ;相乘,结果在AX中 mov bx,10 ;准备除以10 mov si,2 ;循环2次,最大到十位 (乘法表最大为81,所以最大到十位) toDec: ;把各个位转换为数值,如ax中的81,转换为 8,1存在内存中 mov dx,0 div bx ;除10法得到各个位上的数值 mov [buf+si],dl ;余数为该位上的值,第一次循环为个位,第二次为十位...;存到内存中 dec si cmp ax,0 ;商是否为0,为0算法结束 ja toDec output: ;输出内存中存放的转换数值数 inc si mov dl,[buf+si] add dl,30h ;转为ascii mov ah,2 int 21h cmp si,2 jb output mov dl,20h mov ah,2 int 21h loop s2 ;内层循环结束 lea dx,crlf ;输出回车换行 mov ah,9 int 21h pop cx pop cx ;还原外层计数 loop s1 mov ah,1 ;停留等待结束 int 21h MOV AH,4CH INT 21H CODES ENDS END START