80x86汇编语言编程:显示杨辉三角形
扫描二维码
随时随地手机看文章
看到一个要求输出“杨辉三角形”的题目:
循着给出的链接,找到了百度文库,看了一篇又一篇文章、程序,感觉好像是一个赛着一个的罗嗦。
杨辉三角形,大家都知道,排列形状如下:
1 1
1 2 1
1 3 3 1
1 4 6 4 1
1 5 10 10 5 1
1 6 15 20 15 6 1
… … … …
各个元素的数值,其排列的规律也很简单,就是上一行的两个相邻元素之和。
按照这个规律,最左边和最右边,还应该各有一列零。当然,零就不显示了。
有人总结的规律,则要高深的多,竟然用上了排列组合的公式,呵呵,这样一来,编程,还能简单得了吗?
计算任意一行,都要把上一行的两个相邻数据,相加、保存。相加的和如果为零,这一行,就计算完毕了。
比如,上一行是 1 2 1,就可以这样算:
1.先用 0 加上 1,这里的 0,就是不显示的《左边元素》,1,就是《右边元素》,即第一个元素。和为 1,应该存入第一个元素的位置。
但是,别忙,这第一个元素,将来还要和它右边的相加,所以要先保存它之后,再存放刚才的和。
2.再用刚保存的 1,当做《左边元素》,用 2 当做《右边元素》,相加为 3;在预先保存了 2 之后,把 3 存入 2 的位置。
3.再用刚保存的 2,当做《左边元素》,用 1 当做《右边元素》,相加为 3;在预先保存了 1 之后,把 3 存入 1 的位置。
4.再用刚保存的 1,当做《左边元素》,用 0 当做《右边元素》,相加为 1;在预先保存了 0 之后,把 1 存入 0 的位置。
5.再用刚保存的 0,当做《左边元素》,其《右边元素》显然也是 0,相加为 0;结束运算。
每一行,都这样计算,算出来的结果,可以当场输出。
想要输出多少行,就这样算多少遍。
经过推算,第 19 行,其最大的元素,就超过了 65535。大于 65535 的数字,用 16 位机来计算,难度就明显加大了。
那么,用 8088 CPU 汇编语言编程来计算杨辉三角形,最大的行数,做而论道认为还是以 18 行为好。
;做而论道用汇编语言编写的输出《杨辉三角形》的程序如下:
;=====================================
DATAS SEGMENT
tmp1 DW 1, 20 DUP(0) ;定义空间用于运行过程中临时存储数据
TITL DB 0AH, 0DH, '------------------------------------------'
DB 0AH, 0DH, ' YangHui triangel'
DB 0AH, 0DH, '------------------------------------------', 0AH, 0DH
DB 'Please input the output LineNumber [1~18]: $'
X DW ?
DATAS ENDS
;--------------------------------
CODES SEGMENT
ASSUME CS:CODES, DS:DATAS
START:
MOV AX, DATAS
MOV DS, AX
;--------------------------------
LEA DX, TITL
MOV AH, 9
INT 21H
CALL IN_NUM ;输入行数
;------------------------
MOV CX, X ;取来刚输入的数字
CMP CX, 0
JZ EXIT ;判断是否符合范围要求
CMP CX, 18
JA EXIT
CALL CR_LF ;回车换行
CALL CR_LF
M_LOP: ;CX=1~18
LEA SI, tmp1
MOV BX, 0
CALL YangHui ;输出一行
CALL CR_LF
LOOP M_LOP ;循环1~18次
;--------------------------------
EXIT:
MOV AH, 4CH
INT 21H
;=====================================
YangHui: ;计算杨辉三角形
MOV AX, [SI] ;取出数据
ADD AX, BX ;加上《左边数据》
MOV BX, [SI] ;再次取出数据,当做下次的《左边数据》
MOV [SI], AX ;保存和
JZ END_YH ;为零就停止
ADD SI, 2
CALL PRINT_AX ;输出
CALL SPACE
JMP YangHui ;循环
END_YH:
RET ;一行,计算完毕。 这个算法,是不是很简单 ?
;=====================================
IN_NUM: ;输入数字
MOV X, 0 ;先清零
MOV CX, 2 ;输入2位
IN_X:
MOV AH, 7 ;输入单个字符
INT 21H
CMP AL, 13
JE END_IN ;结束
CMP AL, '0'
JB IN_X ;小于'0',不是数字
CMP AL, '9'
JA IN_X
MOV DL, AL
MOV AH, 2 ;显示单个字符
INT 21H
MOV AL, DL
SUB AL, '0' ;还原为数字
MOV AH, 0
MOV SI, AX ;暂存新数据.
;
MOV AX, X
MOV BX, 10 ;老数据乘以10
MUL BX
ADD AX, SI ;加上新数据
MOV X, AX ;保存
LOOP IN_X ;继续输入
END_IN:
RET
;=====================================
PRINT_AX:
PUSH BX
PUSH CX
PUSH DX
MOV BX, 10
MOV CX, 0
P_LOP1:
MOV DX, 0
DIV BX
INC CX
PUSH DX
CMP AX, 0
JNZ P_LOP1
MOV AH, 2
P_LOP2:
POP DX
ADD DL, '0'
INT 21H
LOOP P_LOP2
POP DX
POP CX
POP BX
RET
;=====================================
CR_LF: ;显示回车换行
PUSH AX
PUSH DX
MOV AH, 2
MOV DL, 13
INT 21H
MOV DL, 10
INT 21H
POP DX
POP AX
RET
;=====================================
SPACE: ;显示空格
PUSH AX
PUSH DX
MOV AH, 2
MOV DL, ' '
INT 21H
POP DX
POP AX
RET
;=====================================
CODES ENDS
END START
程序执行的结果:
c:masm510> M1
------------------------------------------
YangHui triangel
------------------------------------------
Please input the output LineNumber [1~18]: 18
1 1
1 2 1
1 3 3 1
1 4 6 4 1
1 5 10 10 5 1
1 6 15 20 15 6 1
1 7 21 35 35 21 7 1
1 8 28 56 70 56 28 8 1
1 9 36 84 126 126 84 36 9 1
1 10 45 120 210 252 210 120 45 10 1
1 11 55 165 330 462 462 330 165 55 11 1
1 12 66 220 495 792 924 792 495 220 66 12 1
1 13 78 286 715 1287 1716 1716 1287 715 286 78 13 1
1 14 91 364 1001 2002 3003 3432 3003 2002 1001 364 91 14 1
1 15 105 455 1365 3003 5005 6435 6435 5005 3003 1365 455 105 15 1
1 16 120 560 1820 4368 8008 11440 12870 11440 8008 4368 1820 560 120 16 1
1 17 136 680 2380 6188 12376 19448 24310 24310 19448 12376 6188 2380 680 136 17 1
1 18 153 816 3060 8568 18564 31824 43758 48620 43758 31824 18564 8568 3060 816 153 18 1
c:masm510>
不知道能否有人来验算一下这些数据是否正确。