题目要求如下:输入多个参数,每个参数间以空格隔开,最后以回车结束输入,要求输出指定参数位置的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 ; 用于保存循环次数