前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >汇编(从键盘接收若干个 N 位的十进制数值(0~65535),并以不同进制显示其和。)

汇编(从键盘接收若干个 N 位的十进制数值(0~65535),并以不同进制显示其和。)

原创
作者头像
用户9372190
发布2022-01-10 21:05:05
7330
发布2022-01-10 21:05:05
举报
文章被收录于专栏:汇编汇编

@toc


题目

从键盘接收若干个 N 位的十进制数值(0~65535),并以二进制、十进制、十六进制三种数制形式显示其和。

要求:

(1)用子程序实现一个 N 位十进制数值的输入,在主程序的循环结构

中调用该子程序;

(2)当用户未输入数值,直接回车时,结束输入;

(3)输出的数据为多位十进制数据,而机器内部计算的和是十六进制形式,需要进行数制转换,然后以十进制字符串的形式输出结果;

(4)程序中要求有必要的提示信息。


运行示例

在这里插入图片描述
在这里插入图片描述

代码

代码语言:txt
复制
DATA SEGMENT

    STR1 DB "Please input a number: $"

    STR2 DB "The sum is: $"

    CRLF DB 0AH,0DH,'$'   ;换行

    COUNT DW 0   ;保存所有输入的真实和

    DIVNUM DW 10  

    DIVNUM1 DW 16

    MULNUM DW 10

    RESULT DB 5 DUP(?)

    RESULT1 DB 5 DUP(?)

    KONGGE DB 32,32,32,32,32,32,32,32,32,32,32,32,'$' ;输出多个空格,对齐时使用

    TEMP DW ?

    ARRAY DB '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F' ;用于输出十六进制形式时,用下标进行对照

DATA ENDS

CODE SEGMENT 

ASSUME CS:CODE,DS:DATA

START:

    MOV AX,DATA

    MOV DS,AX

    

LOOP1:

    CALL GET

    CMP CX,0

    JZ ENDINPUT

    ADD COUNT,BX

    JMP LOOP1

    

ENDINPUT:

    LEA DX,CRLF

    MOV AH,9

    INT 21H

    

    LEA DX,STR2

    MOV AH,9

    INT 21H



TWO:

    MOV BX,COUNT

    MOV TEMP,0

LOOPTWO:

    CMP TEMP,16

    JZ TEN

    SAL BX,1

    JNC OUT0

    MOV AH,02H

    MOV DL,'1'

    INT 21H

    ADD TEMP,1

    JMP LOOPTWO

    

OUT0:

    MOV AH,02H

    MOV DL,'0'

    INT 21H

    ADD TEMP,1

    JMP LOOPTWO



    

TEN:

    MOV AH,02H

    MOV DL,'B'

    INT 21H

    

    LEA DX,CRLF

    MOV AH,9

    INT 21H

    

    LEA DX,KONGGE

    MOV AH,9

    INT 21H

    

    MOV AX,COUNT

    MOV SI,0

    MOV DX,0

LOOP3:

    DIV DIVNUM; AX...DX

    MOV RESULT[SI],DL   ;因为余数小于10,所以DH=0

    CMP AX,0

    JZ NEXT

    MOV DX,0

    ADD SI,1

    JMP LOOP3

    

NEXT:    

    ADD SI,1

    MOV CX,SI

    SUB SI,1



LOOP4:

    ADD RESULT[SI],30H

    MOV AH,02H

    MOV DL,RESULT[SI]

    INT 21H

    SUB SI,1

    LOOP LOOP4

    

    

    MOV AH,02H

    MOV DL,'D'

    INT 21H

    

    LEA DX,CRLF

    MOV AH,9

    INT 21H

    

    LEA DX,KONGGE

    MOV AH,9

    INT 21H

    

    

SIXTEEN:    

    MOV AX,COUNT

    MOV CX,4

    MOV SI,0

    MOV DX,0

LOOPM:

    DIV DIVNUM1; AX....DX

    MOV RESULT1[SI],DL   ;虽说余数放在DX里,但是余数不会超过十五,所以DH为0

    CMP AX,0

    JZ T

    MOV DX,0

    ADD SI,1

    LOOP LOOPM

T:    

    ADD SI,1

    MOV CX,SI

    SUB SI,1

    

LOOP5:

    MOV BL,RESULT1[SI]

    MOV BH,0

    MOV DI,BX

    

    MOV AH,02H

    MOV DL,ARRAY[DI]

    INT 21H

    SUB SI,1

    LOOP LOOP5

    



    MOV AH,02H

    MOV DL,'H'

    INT 21H

    

    LEA DX,CRLF

    MOV AH,9

    INT 21H

    

    

    MOV AX,4C00H

    INT 21H

    

GET PROC ;无输入值,无输出,但是将结果存放在BX中

    LEA DX,STR1

    MOV AH,9

    INT 21H

    

    MOV CX,0;CX用于计数,用于判断这次输入是不是只输入了回车

    MOV BX,0;用BX保存输入的数字最后的真实值

LOOPT:

    MOV AH,1

    INT 21H

    

    CMP AL,0DH

    JZ OVER

    

    MOV CX,1

    MOV AH,0

    SUB AL,30H

    ADD AX,BX

    MUL MULNUM;DW类型和DW类型相乘,高十六位放在DX中的,第十六位放在AX

    MOV BX,AX

    JMP LOOPT

    

OVER:

    MOV AX,BX

    DIV DIVNUM

    MOV BX,AX

    RET

GET ENDP

        

CODE ENDS

END START

解释

1、输入部分

代码语言:txt
复制
LOOP1:

    CALL GET

    CMP CX,0

    JZ ENDINPUT

    ADD COUNT,BX ;将每次真实的NUM添加到COUNT里

    JMP LOOP1

    

ENDINPUT:

    LEA DX,CRLF;换行

    MOV AH,9

    INT 21H

    

    LEA DX,STR2;输出The sum is:

    MOV AH,9

    INT 21H
代码语言:txt
复制
GET PROC ;无输入值,无输出,但是将结果存放在BX中

    LEA DX,STR1

    MOV AH,9

    INT 21H

    

    MOV CX,0;CX用于计数,用于判断这次输入是不是只输入了回车

    MOV BX,0;用BX保存输入的数字最后的真实值

LOOPT:

    MOV AH,1

    INT 21H

    

    CMP AL,0DH

    JZ OVER

    

    MOV CX,1

    MOV AH,0

    SUB AL,30H

    ADD AX,BX

    MUL MULNUM;DW类型和DW类型相乘,高十六位放在DX中的,第十六位放在AX

    MOV BX,AX

    JMP LOOPT

    

OVER:

    MOV AX,BX

    DIV DIVNUM

    MOV BX,AX

    RET

GET ENDP

整体思想

这一题和上一题不一样的地方就是现在输入的不是单个十进制(0~9)的数

这里我用的是接收用户输入的一个一个字符,比如输入6552,接收第一个字符6,把6乘10,放在一个寄存器BX中;再接收5,将BX+5,那么现在BX中的值就是65了,再将BX乘10(这里的乘10及后面的乘都借助AX);再接收5,将BX+5,那么现在BX中的值就是655了,再将BX乘10;再接收2,将BX+2,现在BX为6552,将BX乘10,

因为我是

代码语言:txt
复制
MOV AX,BX

MUL MULNUM  

MOV BX,AX

(如果乘10之后没有超过65535的话,就用不到DX),现在DX:AX中的值是65520 。现在已经接收完了,用户输入回车,退出输入字符的循环,将DX:AX除10即可

逐步解释

代码语言:txt
复制
LOOP1:

    CALL GET

    CMP CX,0

    JZ ENDINPUT

    ADD COUNT,BX

    JMP LOOP1

首先一个循环CALL GET

看看GET子程序

代码语言:txt
复制
    LEA DX,STR1

    MOV AH,9

    INT 21H

    

    MOV CX,0;CX用于计数,用于判断这次输入是不是只输入了回车

    MOV BX,0;用BX保存输入的数字最后的真实值

输出STR1,这里我用CX来作为判断,因为用户只输入一个回车的话代表用户结束了整个输入部分,如果用户输入6553再输入回车,代表只是结束这一次输入,会继续进行下一个数的输入。所以我这里就用CX判断回车之前有没有输入别的数

代码语言:txt
复制
LOOPT:

    MOV AH,1 ;用户输入字符

    INT 21H

    

    CMP AL,0DH ;判断是不是回车,如果是回车则退出循环,这是退出循环的唯一条件

    JZ OVER

    

    MOV CX,1 ;不是回车,证明现在已经有数字的输入了,所以CX为1,下一次用户还会再进行输入一个完整的NUM

    MOV AH,0

    SUB AL,30H ;AX保存输入字符的真实值

    ADD AX,BX ;

    MUL MULNUM;DW类型和DW类型相乘,高十六位放在DX中的,第十六位放在AX

    MOV BX,AX

    JMP LOOPT

    

OVER:

    MOV AX,BX

    DIV DIVNUM

    MOV BX,AX

看注释,和刚刚的整体思想中已经说清楚了


2、输出十六进制

以输出十六进制为例

其实输出部分都蛮简单的

代码语言:txt
复制
SIXTEEN:    

    MOV AX,COUNT;将和赋给AX

    MOV CX,4;让CX为4作为循环次数,因为是16位的,转换成十六进制就是4位

    MOV SI,0 ;用做变址寄存器,作为指针

    MOV DX,0 

LOOPM:

    DIV DIVNUM1; AX....DX

    MOV RESULT1[SI],DL   ;虽说余数放在DX里,但是余数不会超过十五,所以DH为0

    CMP AX,0

    JZ T

    MOV DX,0

    ADD SI,1

    LOOP LOOPM

T:    

    ADD SI,1

    MOV CX,SI

    SUB SI,1

    

LOOP5:

    MOV BL,RESULT1[SI]

    MOV BH,0

    MOV DI,BX

    

    MOV AH,02H

    MOV DL,ARRAY[DI]

    INT 21H

    SUB SI,1

    LOOP LOOP5

    



    MOV AH,02H

    MOV DL,'H'

    INT 21H

逐步解释

代码语言:txt
复制
LOOPM:

    DIV DIVNUM1; AX....DX

    MOV RESULT1[SI],DL   ;虽说余数放在DX里,但是余数不会超过十五,所以DH为0

    CMP AX,0

    JZ T

    MOV DX,0

    ADD SI,1

    LOOP LOOPM

DIV DIVNUM1时候要注意的,除数是DX类型的时候,被除数默认为DX:AX,商放在AX,余数放在DX中;除数是DB类型的时候,被除数默认为AX,商放在AL,余数放在AH。那么这里为什么要让除数是DW类型的呢,因为比如6552除10之后,商是655,余数是2,AL是8位,655超出范围了,这就会出现错误了。所以用DW类型的除数

循环取余,放在一个数组里面

如果AX(AX保存的是商)为0,证明已经全部放完了,没有了,即可退出循环了,到输出十六进制的部分了。

注意每次循环末尾要MOV DX,0 ,因为DX会做一会被除数的高位,而刚才余数也是放在DX里面的

代码语言:txt
复制
T:    

    ADD SI,1

    MOV CX,SI ;CX作为循环次数,等于数组最后一个数的下标加1

    SUB SI,1

    

LOOP5:

    MOV BL,RESULT1[SI]

    MOV BH,0

    MOV DI,BX

    

    MOV AH,02H

    MOV DL,ARRAY[DI]

    INT 21H

    SUB SI,1

    LOOP LOOP5

    



    MOV AH,02H

    MOV DL,'H'

    INT 21H

逆序输出即可,无难点


Bug

在这里插入图片描述
在这里插入图片描述

输入一个字符之后没法删除重新输入,输入的时候,比如我这个数输错了,554我输成555了,我没法进行修改。

拟解决方案

用字符串来承接用户输入的数,比如用户输入6553,我就定义一个字符串,把用户的输入的65535放进去,再调用一个子程序,把这个字符串转换成真正的数

只有输入部分发生了改变

代码语言:txt
复制
MOV COUNT,0

LOOP1:

    CALL INPUT   ;这个问题非常关键,就是在这里我有一点问题就是不确定在正常输入的时候,按下回车,回车会不会保存到NUM里面

    MOV SI,2

    CMP NUM[SI],0DH ;回车会被保存在NUM数组的第三个字节位置

    JZ ENDINPUT

    MOV SI,1

    MOV CX,word ptr NUM[SI] ;将NUM的真实长度送个CX,作为循环次数

    SUB CX,1  ;因为真实长度还有除去回车

    

    ADD CX,1

    MOV SI,CX   ;这三行是为了,把SI定位对NUM数组的倒数第二个位置(最后一个是回车)

    SUB CX,1

     

    MOV BX,0

    CALL TURN   ;将字符串NUM转换成真正有意义的NUM

    ADD COUNT,BX

    

    LEA DX,CRLF

    MOV AH,9

    INT 21H

    JMP LOOP1
代码语言:txt
复制
INPUT PROC

    LEA DX,STR1

    MOV AH,9

    INT 21H

    

    LEA DX,NUM

    MOV AH,0AH

    INT 21H

    

    RET

INPUT ENDP



TURN PROC

    PUSH AX

    

    MOV TEMP,1

    

    ;我想用BX来暂时NUM数组中的真实数据

LOOPN:

    MOV AL,NUM[SI]

    SUB AL,30H

    MOV AH,0

    MUL TEMP ;AX\*TEMP(DW)->DX:AX    因为我知道COUNT最大容量为16位,所以必然用不到DX

    ADD BX,AX

    SUB SI,1

    

    MOV AX,TEMP

    MUL MULNUM

    MOV TEMP,AX

    LOOP LOOPN



    

    POP AX

    RET

这个办法也基本上能成功的,但就是有一个问题没有得到解决,就是我每次输入字符串,我在DATA SEGMENT里面只能定义一个字符串,那么下一次输入会覆盖这个字符串。如果这次输入的字符串,比上次的短,那么字符串保存的真实长度就不准确,且会多出上一个字符串没有被覆盖的部分。

所以总的来说,就是如何将字符串置空的问题。


如果有错误,欢迎指正啊,感谢观看!!!

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 题目
  • 运行示例
  • 代码
  • 解释
    • 1、输入部分
      • 整体思想
      • 逐步解释
    • 2、输出十六进制
      • 逐步解释
      • 拟解决方案
  • Bug
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
http://www.vxiaotou.com