微机原理:求解大数阶乘

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

一:实验目的

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

二:实验要求

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:大数相乘逻辑

大数阶乘逻辑

相关文章
|
1月前
|
监控 Cloud Native 网络性能优化
122_集群管理:Slurm配置 - 优化大规模训练调度
在2025年,大规模语言模型(LLM)的训练已经进入到超大规模时代,模型参数量达到数千亿甚至万亿级别,训练过程需要动用数百甚至数千个GPU/TPU。在这种情况下,高效的集群管理系统成为训练成功的关键基础设施。Slurm(Simple Linux Utility for Resource Management)作为目前最流行的开源作业调度系统,广泛应用于科研机构和大型科技公司的超级计算集群中。
|
4月前
|
人工智能 自然语言处理 文字识别
快手封号多久能恢复正常?
快手账号封禁恢复全流程技术解析
从零开始做逆变器系列 ( 二 ): 单极性、双极性、单极性倍频SPWM
从零开始做逆变器系列 ( 二 ): 单极性、双极性、单极性倍频SPWM
|
网络协议
关于socket bind的理解
socket bind的ip和port的选择
3209 0
|
SQL 数据挖掘 关系型数据库
Hive 高阶--分组窗口函数--OLAP 相关分组函数(GROUPING SETS,CUBE,ROLLUP)|学习笔记
快速学习 Hive 高阶--分组窗口函数--OLAP 相关分组函数(GROUPING SETS,CUBE,ROLLUP)
453 0
Hive 高阶--分组窗口函数--OLAP 相关分组函数(GROUPING SETS,CUBE,ROLLUP)|学习笔记
|
存储 运维 自然语言处理
Cassandra 的过去、现在、未来
11月16日在北京,由DataFun和阿里云联合举办的首场Cassandra中文社区线下meetup,阿里云高级技术专家陈江分享了Cassandra的发展历程、优势特点、适合的使用场景、不推荐的场景,以及即将发布的4.0特性。
2736 0
Cassandra 的过去、现在、未来
|
关系型数据库 应用服务中间件 Linux
centos7编辑安装php7.启用php扩展
centos7编辑安装php7.启用php扩展
749 0
centos7编辑安装php7.启用php扩展
|
关系型数据库 MySQL 索引
MySQL · 捉虫动态 · order by limit 造成优化器选择索引错误
问题描述 bug 触发条件如下: 优化器先选择了 where 条件中字段的索引,该索引过滤性较好; SQL 中必须有 order by limit 从而引导优化器尝试使用 order by 字段上的索引进行优化,最终因代价问题没有成功。 复现case 表结构 create table t
8275 0
|
API 数据安全/隐私保护 Hbase
Dremio与Drill的对比
1.简述 Dremio与Drill简述 2.区别 a).数据源支持 使用最新版本Dremio 3.3.1和Drill 1.16.0Dremio3.1.3版本开始不支持HBase,将来会开源社区版HBase连接器 b).
3231 0