微机原理:求解大数阶乘

简介: 微机原理:求解大数阶乘

一:实验目的

用汇编语言编写设计一个求解大数的阶乘的精确值的程序。

二:实验要求

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

2:实验结果

9的阶乘
14的阶乘
15的阶乘
100的阶乘

3:大数相乘逻辑

大数阶乘逻辑

相关文章
|
4月前
|
算法 C#
C#实战 | 求解《丘建算经》百鸡问题
【7月更文挑战第9天】《丘建算经》的百鸡问题是一个经典的不定方程问题,用C#解决时,通过三重嵌套循环穷举公鸡、母鸡和小鸡的组合。代码示例中,外层循环分别对应公鸡和母鸡,而小鸡数量由总钱数和已知鸡种计算得出,避免了额外的内层循环。使用`if`判断确保总数量正确。注意,除法运算可能导致整数截断错误,需使用3.0保证浮点数除法的准确性。这种方法虽然效率较低,但能确保找到所有可行解。
45 1
C#实战 | 求解《丘建算经》百鸡问题
|
人工智能 算法
算法提高:组合数学| 容斥原理常见应用
容斥原理常见的问题如下。 (1) 篮球、羽毛球、网球三种运动,至少会一种的有22人,会篮球的有15人,会羽毛球的有17人,会网球的有12人,既会篮球又会羽毛球的有11人,既会羽毛球又会网球的有7人,既会篮球又会网球的有9人,那么三种运动都会的有多少人? (2) 《西游记》《三国演义》《红楼梦》三大名著,至少读过其中一本的有20人,读过《西游记》的有10人,读过《三国演义》的有12人,读过《红楼梦》的有15人,读过《西游记》《三国演义》的有8人,读过《三国演义》《红楼梦》的有9人,读过《西游记》《红楼梦》的有7人。问三本书全都读过的有多少人?
158 0
算法提高:组合数学| 容斥原理常见应用
|
6月前
|
Shell
【高数定积分求解旋转体体积】 —— (上)高等数学|定积分|柱壳法|学习技巧
【高数定积分求解旋转体体积】 —— (上)高等数学|定积分|柱壳法|学习技巧
114 0
|
机器学习/深度学习 算法
算法提高:组合数学| 卡特兰数的实现
卡特兰数列是组合数学中在各种计数问题中常出现的数列,其前几项为1,1,2,5,14,42,132,429,1430,4862,16796,58786,208012…… 卡特兰数首先是由欧拉在计算对凸n边形的不同的对角三角形剖分的个数问题时得到的,即在一个凸n边形中,通过不相交于n边形内部的对角线,把n边形拆分成若干三角形,不同的拆分数用Hn表示,Hn即卡特兰数。
145 0
算法提高:组合数学| 卡特兰数的实现
|
资源调度
数论整理之算数基本定理de变形
数论整理之算数基本定理de变形
|
人工智能 算法
算法每日一题——第六天——干草堆(差分)
算法每日一题——第六天——干草堆(差分)
算法每日一题——第六天——干草堆(差分)
洛谷P1067-多项式输出(模拟好题!)
洛谷P1067-多项式输出(模拟好题!)
[物理学与PDEs]第5章习题10 多凸函数一个例子
证明函数 $$\bex \hat W({\bf F})=\sedd{\ba{ll} \cfrac{1}{\det{\bf F}},&if\ \det{\bf F}>0,\\ +\infty,&if\ \det{\bf F}\leq 0 \ea} \eex$$ 是多凸的.
824 0
|
资源调度
[物理学与PDEs]第3章习题3电磁场的矢势在 Lorentz 规范下满足的方程
设 $\phi$ 及 ${\bf A}$ 分别为电磁场的标势及矢势 (见第一章 $\S$ 6). 试证明: 若 $\phi$ 及 ${\bf A}$ 满足条件 $$\bex \phi+\cfrac{1}{\sigma \mu_0}\Div{\bf A}=0, \eex$$ 则方程 (2.
637 0
|
Perl
[物理学与PDEs]第3章习题4 理想磁流体的能量守恒方程
试证明: 对理想磁流体, 能量守恒方程 (4. 14) 可以写为如下形式: $$\beex \bea \cfrac{\p}{\p t}&\sex{\rho e+\cfrac{1}{2}\rho u^2 +\cfrac{1}{2}\mu_0H^2}\\ +\sum_{k=1}^3 \cfrac{\p}...
900 0