一:实验目的
用汇编语言编写设计一个求解大数的阶乘的精确值的程序。
二:实验要求
1:基本要求
用汇编语言编写设计一个求解大数的阶乘的精确值的程序。
2:设计提示
采用字节型数组存放阶乘结果的每个数字位,采用逐位相乘,再对每一位规格化来实现。
3:提升要求
输出阶乘结果的位数和尾零的个数。
三:实验过程
1:源代码
include vcIO.inc
.data
infoMsg byte '请输入你要求的阶乘:',13,10,0
resultMsg byte '阶乘结果为:',13,10,0
errorMsg byte '你输入的值小于9,无法求取阶乘',13,10,0
illegalMsg byte '你输入的值小于0,无法求取阶乘',13,10,0
zeroMsg byte '尾数0的个数为',13,10,0
total byte '总位数为',13,10,0
; 存放要求阶乘的数字
inputNum dword 0
; 存放结果的数组长度为100000可以根据需求进行适量的更改
bufferLength dword 100000 dup (0),0
; 存放结果数组有效数字的个数,打印时候需要以其作为度量打印出来
bufferValidLength dword 1
; 存放进位
carry dword 0
dFormat byte '%d',0
strReturn byte '#',10,0
.code
main proc
pushad
Start:
mov eax,1
mov bufferLength[0],eax
pushad
; printf(infoMsg)
invoke printf,offset infoMsg
popad
; scanf(inputNum)
invoke scanf,offset dFormat,offset inputNum
; if inputNum < 0: jump Illegal(输入不合法)
mov eax,inputNum
cmp eax,0
jl Illegal
; 用于判断所求阶乘的值,如果这个值小于2(eg:0,1)那么结果是1
mov ebx,2
; 开始外部循环(for(ebx(begin) = 2; ebx(begin) <= inputNum; ebx++))
Outer:
; ebx:当前需要计算的数字(begin)
; if ebx > inputNum: jump Finish(程序结束)
cmp ebx,inputNum
; 完成计算
jg Finish
mov ecx,1
mov eax,0
; 默认第0位的所要加的进位为0
mov carry,eax
; 主要作用计算一个"大数"和一个数字的"乘积"
CalFactorIal:
; if ecx > bufferValidLength: jump CalCarry
cmp ecx,bufferValidLength
jg CalCarry
; 当前的数字类型的变量存放在ebx中(也是需要和字符数组乘的数字)
mov eax,ebx
; 将eax*bufferLength[ecx*4-4]存放在eax中
mul bufferLength[ecx*4-4]
; 给结果加上进位
add eax,carry
; 保存当前ebx的值即为当前数字变量的值
push ebx
; eax(ebx * bufferLength[]) / ebx(10)
mov ebx,0ah
div ebx
pop ebx
; 余数保存在当前结果数组中
mov bufferLength[ecx*4-4],edx
; 除数放在carry中更新carry这个数字
mov carry,eax
; 存放当前操作的下标位置
inc ecx
jmp CalFactorIal
; 处理进位
CalCarry:
; if carry == 0: next loop
cmp carry,0
jz LoopNext
; bufferValidLength += 1(有进位,有效长度加1)
mov eax,1
add bufferValidLength,eax
; eax:记录商,edx:记录余数
; eax(carry) / ebx(10)
mov edx,0
mov eax,carry
push ebx
mov ebx,0ah
div ebx
pop ebx
push edx
mov eax,bufferValidLength
push ebx
mov ebx,04h
; eax = eax * ebx(4)
mul ebx
pop ebx
; eax = eax - 4
sub eax,4
pop edx
; 保存余数到数组
mov bufferLength[eax],edx
; eax(carry) / ebx(10)
mov edx,0
mov eax,carry
push ebx
mov ebx,0ah
div ebx
pop ebx
; carry = eax
mov carry,eax
jmp CalCarry;循环保存余数直到进位只剩个位
; 进入下一次循环(ebx++)
LoopNext:
inc ebx
jmp Outer
; bufferValidLength记录的就是结果字符串的长度,也就是要打印的结果的长度
Finish:
mov ecx,bufferValidLength
pushad
invoke printf,offset resultMsg
popad
; 打印数字
PrintResult:
; if ecx <= 0:jump PrintTotal
cmp ecx,0
jle PrintTotal
mov eax,bufferLength[ecx*4-4]
pushad
invoke printf,offset dFormat,eax
popad
xor eax,eax
dec ecx
jmp PrintResult
; 输入内容不合法(inputNum < 0),无法求阶
Illegal:
pushad
invoke printf,offset illegalMsg
popad
; 打印总位数(总位数为:%d)
PrintTotal:
invoke printf,offset strReturn
invoke printf,offset total
mov eax,bufferValidLength;
invoke printf,offset dFormat,eax
mov edi,0;
mov ecx,1
; 求解末尾0的个数
Zero:
mov eax,bufferLength[ecx*4-4]
cmp eax,0
; if lastNum != 0:jump PrintZero
jne PrintZero
; edi:记录尾数0的个数,ecx:控制尾数的下标
inc edi
inc ecx
; if ecx >= 有效下标:大数已比较完
cmp ecx,bufferValidLength
jge EndMain
; 计算下一个尾数
jmp Zero
; 打印0的个数(尾数0的个数为:%d)
PrintZero:
pushad
invoke printf,offset strReturn
invoke printf,offset zeroMsg
popad
invoke printf,offset dFormat,edi
EndMain:
popad
ret
main endp
end main