nasm汇编语言小程序:计算多个指定位置的Fibonacci值

时间:2021-04-04 02:47:41

题目要求如下:输入多个参数,每个参数间以空格隔开,最后以回车结束输入,要求输出指定参数位置的Fibonacci值

我的编程环境:Ubuntu 14.04 64位系统 + DOSBox + NASM + gedit

首先,考虑输入问题,我采取的是逐个读入字符的方式,读到空格则代表上一个数据输入完毕,读入回车则代表所有数据输入完毕:

    1)利用buffer存取每一个数据,将buffer初始化为0,每读入一个数字后buffer = buffer*10 + digit,其中digit为刚刚读入数字的值(由于读入是字符,所以digit要减30h)

    2)读入空格后,将buffer压栈,然后将buffer清零,继续执行输入,直到输入回车

之后,处理完所有数据的输入后,将数据出栈,根据出栈顺序计算当前数据对应的Fibonacci值,计算完后跳转到输出,输出完后再跳转回下一个数据的计算

    1)利用循环计算Fibonacci值,循环次数即为出栈的数据值

    2)单独处理出栈数据为1和2的情况

此处有一问题:出栈数据顺序与输入数据顺序相反,而计算顺序是根据出栈顺序决定的,而且我是在计算完后进行输出,于是输出顺序与输入顺序相反,此处我采用了控制光标(int 10h中的2h)的方法用以控制输出数据的行的位置,实际上计算顺序的确是反的,但显示上是正确的顺序


大数的计算:申请多个内存单元,每个单元存至多99,超过99便进位同时将该单元的值减100


;1 1 2 3 5 8 13 21 34 55 89
org	100h

section .text

start:
	mov		byte[buffer], 0			; 初始化buffer为0
	mov		byte[num_count], 0		; 初始化输入数据个数为0
	mov		byte[color], 07h		; 初始化颜色
	jmp		input

input:
	mov		ah, 07h		; 读入字符(包括控制字符)
	int		21h

	mov		dl, al		; 回显读入字符
	mov		ah, 2h
	int		21h

	cmp		al, 0dh		; 若读入回车则结束输入
	je		analysis

	cmp		al, 20h		; 判断输入字符是否为空格
	je      push_data	; 是空格则压入数据

	sub		al, 30h
	mov		byte[digit], al
	mov		al, byte[buffer]
	mov		bl, 10
	mul		bl
	add		al, byte[digit]	
	mov		byte[buffer], al			; buffer = buffer*10 + digit

	jmp 	input

push_data:
	add		byte[num_count], 1	; 统计输入数据个数
	mov		ah, 0
	mov		al, byte[buffer]
	push	ax					; 数据压栈,此处数据需要是16位

	mov		byte[buffer], 0		; buffer清零

	jmp		input				; 继续输入

analysis:
	add		byte[num_count], 1	; 统计输入数据个数
	mov		ah, 0
	mov		al, byte[buffer]
	push	ax					; 数据压栈,此处数据需要是16位

	mov		dl, 0ah				; 换行
	mov		ah, 02h
	int		21h

	mov		dl, 0dh				; 回车
	mov		ah, 02h
	int		21h

	; 读取光标位置
	mov		ah, 03h
	mov		bh, 0
	int		10h

	mov		byte[row], dh
	sub		byte[row], 1			; 设置输出行的起始位置
	add		dh, byte[num_count]
	mov		byte[final_row], dh		
	sub		byte[final_row], 1		; 设置最后的光标位置

calculate:
	pop		dx	

fibonacci:
	mov		byte[digit_count], 0	; 数字位数初始化为0

	; 初始化a1,a2以及最终结果a3为1
	mov		cx, 15
	set:
		mov		bx, num1
		add		bx, cx
		sub		bx, 1	
		mov		byte[bx],0
		mov		bx, num2
		add		bx, cx
		sub		bx, 1	
		mov		byte[bx], 0
		mov		bx, num3
		add		bx, cx
		sub		bx, 1	
		mov		byte[bx],0
	Loop set
	mov		byte[num1+15], 1
	mov		byte[num2+15], 1
	mov		byte[num3+15], 1

	cmp     dx, 1	; 输入1
    je      output
    cmp		dx, 2	; 输入2
	je		output

	sub		dx, 2	; 输入数大于等于3
	mov		byte[num3+15], 0		; 若输入大于等于3,将最终结果初始化为0

	mov		cx, dx	; 初始化计算Fibonacci循环次数

adding:
	
	push	cx

	mov		byte[cf], 0			; 初始化进位为0
	mov		cx, 16
	next:
		; 计算an=an-1+an-2
		mov		bx, num1
		add		bx, cx
		sub		bx, 1
		mov		al,	byte[bx]
		mov		bx, num2
		add		bx, cx
		sub		bx, 1	
		add		al,	byte[bx]	
		mov		bx, num3
		add		bx, cx
		sub		bx, 1	
		add		al, byte[cf]
		mov		byte[bx], al

		mov		byte[cf], 0		; 进位加完后归0

		cmp		byte[bx], 100	; 每个单元存放的值最多为99,使用十进制的思想
		jb		end
		
		sub		byte[bx], 100
		mov		byte[cf], 1		; 若大于等于100,则进位
	
	end:
	Loop next

	mov		cx, 16
	copy:
		mov		bx, num2
		add		bx, cx
		sub		bx, 1	
		mov		al,	byte[bx]
		mov		bx, num1
		add		bx, cx
		sub		bx, 1	
		mov		byte[bx], al	; 将an-1赋值给an-2
		
		mov		bx, num3
		add		bx, cx
		sub		bx, 1	
		mov		al,	byte[bx]
		mov		bx, num2
		add		bx, cx
		sub		bx, 1	
		mov		byte[bx], al	; 将an赋值给an-1
	Loop copy
	pop		cx

Loop adding

output:
	mov		cx, 16
	divide:	
		mov		bx, num3
		add		bx, cx
		sub		bx, 1
		mov		al,	byte[bx]

		mov		ah, 0
		mov		dl, 10
		div		dl
		movzx	dx, ah
		push	dx
		mov		ah, 0
		mov		dl, 10
		div		dl
		movzx	dx, ah
		push	dx
	Loop divide

	; 设置光标位置
	mov		ah, 02h
	mov		bh, 0
	mov		dh, byte[row]
	add		dh, byte[num_count]		; 当前光标位置 = 起始位置+第x个数据
	mov		dl, 0
	int		10h

	mov		cx, 32					; 32=2*16,每个单元最多存两位(99),共16个单元
	add		byte[color], 1
	mov		byte[flag_nz], 0		; 用于标记遇到第一个非零的数字

print:
	mov		word[loop_time], cx	; 保存循环次数

	; 设置颜色
	mov		ah, 09h
	mov		bh, 0
	mov 	bl, byte[color]		
	mov		cx, 1
	int 	10h

	pop		dx

	cmp		byte[flag_nz], 1
	je		not_zero				; 遇到非零数后便正常输出剩下所有数字
	cmp		dx, 0
	je		zero					; 若一直未遇到非零数便跳过输出
	
	mov		byte[flag_nz], 1		; 遇到非零数改变标志

not_zero:
	add		dx, 30h
	mov		ah, 2h
	int		21h

zero:
	mov		cx, word[loop_time]		; 恢复循环次数
Loop print

	sub		byte[num_count], 1		; 总数字个数减一
	
	cmp		byte[num_count], 0
	jne		calculate

exit:
	; 设置最后的光标位置
	mov		ah, 02h
	mov		bh, 0
	mov		dh, byte[final_row]
	int		10h

	mov		ax, 4c00h
	int		21h

section .bss

num1		resb	16		; an-2项
num2		resb	16		; an-1项
num3		resb	16		; an项
cf		resb	1		; 进位
flag_nz		resb	1		; 非零标志位
buffer		resb	1		; 之前读入数字的值
digit		resb	1		; 读入的一位数字
num_count	resb	1		; 输入数据的总个数
digit_count	resb	1		; 每个数据的位数
color		resb	1		; 颜色
row			resb	1		; 起始行数
final_row	resb	1		; 最终行数
loop_time	resw	1		; 用于保存循环次数