汇编语言之判断回文数
题目描述:
打印回文数。如果一个数从左边和从右边读都是相同的数,就称它为回文数,例如383。求出500 以内的回文数并输出显示。要求:提示数据范围为0-500;Enter键,换行显示结果。
基本功能:
每输入一个数,都判断是不是回文数(同时伴随着溢出和错误输入判断);若出现溢出或者是错误输入时,程序提示重新输入。
拓展功能:
每输入一个1到500的数,若该数是回文数,则输出打印其中0到该数内的所有回文数;若不是回文数,则输出提示不是回文数,并且结束程序。
基本功能代码:
enterline macro ;定义回车换行的宏指令 mov dl,13 mov ah,2 int 21h mov dl,10 mov ah,2 int 21h endm DATAS SEGMENT input db 'Please input a number between 0 and 500:$' output1 db 'Convertion Success!$' err db 'Illegal input! Please Try Again$' out1 db 'Sorry, the number you entered is more than 500, please try again$' buf db 10,?,10 dup(0) ;定义键盘接收字符缓冲区,最多接收9个字符 len dw ? ;记录输入的数的长度 nop1 db 'The number you entered is not palindrome, bye$' sum dw ? space db ' ' ;空格 flag db 0 test1 db '333$' ;此处输入数据段代码 DATAS ENDS STACKS SEGMENT ;此处输入堆栈段代码 STACKS ENDS CODES SEGMENT ASSUME CS:CODES,DS:DATAS,SS:STACKS START: MOV AX,DATAS MOV DS,AX ;此处输入代码段代码 begin: lea dx,input ;给出输入提示 mov ah,9 int 21h enterline ;回车换行 lea dx,buf ;从键盘接收输入数值放入buf缓冲区(输入操作) mov ah,10 int 21h enterline ;回车换行 push bx ;入栈保护 push cx push dx push si call ascii_num pop si ;退栈 pop dx pop cx pop bx ;接下来是回文数的检测 考虑直接对字符进行回文数的检测 jmp judge ;判断输入的数长度,结果存在cx中,si存入检测的数 judgeovr: cmp flag,0 ;标志是否为输出的那个数 je firstjudge firstjudge: mov flag,1 mov si,0 cmp cx,1 je loop_num cmp cx,2 je len2 cmp cx,3 je len3 len2: lea dx,test1 mov ah,9 int 21h enterline xor ax,ax xor dx,dx mov ax,sum mov bx,10 div bx cmp ax,dx je loop_num jmp not1 ;判断出该数不是回文数 len3: xor ax,ax xor dx,dx xor di,di mov ax,sum mov bx,100 div bx mov di,ax mov ax,dx xor dx,dx mov bx,10 div bx cmp di,dx je loop_num jmp not1 ;判断出该数不是回文数 loop_num: lea dx,output1 mov ah,9 int 21h jmp stop num_ascii: mov ax,si;(有效数值为0~65535) 待转换数放置于AX寄存器中 mov bx,100 ;初始数位权值为100 cov1:xor dx,dx ;将dx:ax中的数值除以权值 div bx mov cx,dx ;余数备份到CX寄存器中 cmp flag,0 ;检测是否曾遇到非0商值 jne nor1 ;如遇到过,则不管商是否为0都输出显示 cmp ax,0 ;如未遇到过,则检测商是否为0 je cont ;为0则不输出显示 nor1: mov dl,al ;将商转换为ascii码输出显示 add dl,30h mov ah,2 int 21h mov flag,1 ;曾遇到非0商,则将标志置1 cont: cmp bx,10 ;检测权值是否已经修改到十位了 je outer ;如果相等,则完成最后的个位数输出显示 xor dx,dx ;将数位权值除以10 mov ax,bx mov bx,10 div bx mov bx,ax mov ax,cx ;将备份的余数送入AX jmp cov1 ;继续循环 outer: mov dl,cl ;最后的个位数变为ascii码输出显示 add dl,30h mov ah,2 int 21h mov dl,space mov ah,2 int 21h jmp loop_num not1: ;不是回文数 lea dx,nop1 mov ah,9 int 21h enterline jmp stop ;如出错则返回起始点重新输入 error: ;给出错误提示(输入不规范) lea dx,err mov ah,9 int 21h enterline jmp begin ;如出错则返回起始点重新输入 yichu: ;超过500范围的提示 lea dx,out1 mov ah,9 int 21h enterline jmp begin ;如出错则返回起始点重新输入 judge: xor ax,ax xor dx,dx xor bx,bx xor cx,cx mov si,sum mov cx,1 ;最初长度赋值为1 mov ax,si ;将检测的数赋值给ax mov bx,10 ;除数赋值10 div bx cmp ax,0 ;相等就跳走 je judgeovr mov cx,2 xor dx,dx mov ax,si ;将检测的数赋值给ax mov bx,100 ;除数赋值10 div bx cmp ax,0 je judgeovr mov cx,3 jmp judgeovr stop: MOV AH,4CH INT 21H ascii_num PROC ;将字符串转成数字的子程序 mov cl,buf+1 ;获取实际键入字符数,置于CX寄存器中 xor ch,ch ;ch清0 mov len,cx ;这里把长度保存下来方便后面使用 xor di,di ;累加器清0 xor dx,dx ;dX寄存器清0 mov bx,1 ;由于从个位数开始算起,因而将所乘权值设为1 lea si,buf+2 ;将si指向接收到的第1个字符位置 add si,cx ;因为从个位算起,所以将si指向最后1个接收到的个位数 dec si ;往回减1使其指向字串最后一个元素 cov:mov al,[si] ;取出个位数给al cmp al,'0' ;边界检查:如果输入不是0-9的数字,就报错 jb error cmp al,'9' ja error sub al,30h ;将al中的ascii码转为数字 xor ah,ah mul bx ;乘以所处数位的权值 cmp dx,0 ;判断结果是否超出16位数范围,如超出则报错 jne error add di,ax ;将形成的数值放在累加器di中 jc error ;如数值超过16位数范围报错 cmp di,500 ja yichu mov sum,di mov ax,bx ;将BX中的数位权值乘以10 mov bx,10 mul bx mov bx,ax dec si ;si指针减1,指向前一数位 loop cov ;按CX中的字符个数计数循环 mov ax,di ;将最终转换结果从di中放置到ax中 EXIT: RET ascii_num ENDP CODES ENDS END START
拓展功能代码:
1 enterline macro ;定义回车换行的宏指令 2 mov dl,13 3 mov ah,2 4 int 21h 5 mov dl,10 6 mov ah,2 7 int 21h 8 endm 9 10 DATAS SEGMENT 11 input db 'Please input a number between 0 and 500:$' 12 err db 'Illegal input! Please Try Again$' 13 out1 db 'Sorry, the number you entered is more than 500, please try again$' 14 buf db 10,?,10 dup(0) ;定义键盘接收字符缓冲区,最多接收9个字符 15 16 nop1 db 'The number you entered is not palindrome, bye$' 17 sum dw ? 18 space db ' ' ;空格 19 flag db 0 ;用于不输出前导0的标志 20 ff db 0 ;用于标记是否为第一次回文数判断 21 zero db 0 ;标志0是否输出过 22 23 ;此处输入数据段代码 24 DATAS ENDS 25 26 STACKS SEGMENT 27 ;此处输入堆栈段代码 28 STACKS ENDS 29 30 CODES SEGMENT 31 ASSUME CS:CODES,DS:DATAS,SS:STACKS 32 START: 33 MOV AX,DATAS 34 MOV DS,AX 35 ;此处输入代码段代码 36 37 begin: 38 lea dx,input ;给出输入提示 39 mov ah,9 40 int 21h 41 enterline ;回车换行 42 43 lea dx,buf ;从键盘接收输入数值放入buf缓冲区(输入操作) 44 mov ah,10 45 int 21h 46 enterline ;回车换行 47 48 push bx ;入栈保护 49 push cx 50 push dx 51 push si 52 call ascii_num ;调用子程序输入数据 53 pop si ;退栈 54 pop dx 55 pop cx 56 pop bx 57 58 mov si,sum ;将输入的数的值先复制给si 59 call judge ;判断输入的数长度,结果存在cx中,si是待检测的数 60 61 62 judgeovr: ;第二次及以后的回文数判断 63 cmp ff,0 ;标志是否为输出的那个数 64 je firstjudge 65 66 cmp cx,1 ;数只有一位时直接输出 67 je num_ascii 68 cmp cx,2 ;数有两位时跳转到两位数的回文判断 69 je len22 70 cmp cx,3 ;数有三位时跳转到三位数的回文判断 71 je len33 72 73 len22: ;两位数的回文判断,判断个位十位是否相同 74 xor ax,ax 75 xor dx,dx 76 mov ax,si 77 mov bx,10 78 div bx 79 cmp ax,dx 80 je num_ascii 81 82 jmp loop_num ;判断出该数不是回文数,跳回loop_num去取下一个数 83 84 len33: ;三位数的回文判断,判断百位个位是否相同 85 xor ax,ax 86 xor dx,dx 87 xor di,di 88 mov ax,si 89 mov bx,100 90 div bx 91 mov di,ax 92 mov ax,dx 93 xor dx,dx 94 mov bx,10 95 div bx 96 cmp di,dx 97 je num_ascii 98 99 jmp loop_num ;判断出该数不是回文数,跳回loop_num去取下一个数 100 101 102 firstjudge: ;对输入的数进行第一次的回文判断 103 mov ff,1 104 mov si,0 ;si从0开始,方便后面inc 105 106 cmp cx,1 ;数只有一位时直接跳转去循环,代表输入的数是回文数 107 je loop_num 108 cmp cx,2 ;数有两位时跳转到两位数的回文判断 109 je len2 110 cmp cx,3 ;数有三位时跳转到三位数的回文判断 111 je len3 112 113 len2: ;两位数的回文判断,判断个位十位是否相同 114 xor ax,ax 115 xor dx,dx 116 mov ax,sum ;将输入的值赋给ax去判断 117 mov bx,10 118 div bx 119 cmp ax,dx 120 je loop_num ;判断该数是回文数,跳转循环 121 122 jmp not1 ;判断出该数不是回文数,跳转notq 123 124 len3: ;三位数的回文判断,判断百位各位是否相同 125 xor ax,ax 126 xor dx,dx 127 xor di,di 128 mov ax,sum ;将输入的值赋给ax去判断 129 mov bx,100 130 div bx 131 mov di,ax 132 mov ax,dx 133 xor dx,dx 134 mov bx,10 135 div bx 136 cmp di,dx 137 je loop_num ;判断该数是回文数,跳转循环 138 139 jmp not1 ;判断出该数不是回文数,跳转not1 140 141 142 loop_num: ;循环:代表输入的数已经是回文数,接下来循环从0—输入的数的回文数打印 143 144 inc si ;每次都去判断,si的变化范围是0—输入的数,每次加1 145 cmp si,sum ;当大于输入的数时跳转停止 146 ja stop 147 148 call judge ;每次si加1后,都要去判断si的长度,其中cx中存长度 149 ;judge判断完长度后,会自动跳转判断回文数和打印数 150 151 jmp loop_num ;不断循环 152 153 zz: ;该段程序是解决输出0的问题 154 mov zero,1 ;0输出过 155 156 mov dl,'0' 157 mov ah,2 158 int 21h 159 160 mov dl,space ;输出空格 161 mov ah,2 162 int 21h 163 164 jmp num_ascii ;输完0后再开始从1开始输出 165 166 num_ascii: ;将num转为ascii 167 cmp zero,0 ;判断0是否输出过,没输出就去输出0 168 je zz 169 170 mov ax,si ;将每次循环计数的si赋值ax去输出 171 mov bx,10 ;初始数位权值为10 172 cmp cx,3 ;若为3位数,则赋权为100 173 je cx_3 174 175 cov1:xor dx,dx ;将dx:ax中的数值除以权值 176 div bx 177 mov cx,dx ;余数备份到CX寄存器中 178 179 cmp flag,0 ;检测是否曾遇到非0商值 180 jne nor1 ;如遇到过,则不管商是否为0都输出显示 181 cmp ax,0 ;如未遇到过,则检测商是否为0 182 je cont ;为0则不输出显示 183 184 nor1: 185 mov dl,al ;将商转换为ascii码输出显示 186 add dl,30h 187 mov ah,2 188 int 21h 189 190 mov flag,1 ;曾遇到非0商,则将标志置1 191 192 cont: 193 cmp bx,10 ;检测权值是否已经修改到十位了 194 je outer ;如果相等,则完成最后的个位数输出显示 195 196 xor dx,dx ;将数位权值除以10 197 mov ax,bx 198 mov bx,10 199 div bx 200 mov bx,ax 201 202 mov ax,cx ;将备份的余数送入AX 203 jmp cov1 ;继续循环 204 205 outer: 206 mov dl,cl ;最后的个位数变为ascii码输出显示 207 add dl,30h 208 mov ah,2 209 int 21h 210 211 mov dl,space ;输出空格 212 mov ah,2 213 int 21h 214 215 jmp loop_num ;每次输出完一个数后,跳回循环去取下一个数 216 217 218 219 cx_3: 220 mov bx,100 ;赋权值为100 221 jmp cov1 222 223 not1: ;不是回文数 224 lea dx,nop1 225 mov ah,9 226 int 21h 227 enterline 228 229 jmp stop ;如输入不是回文数则返回起始点重新输入 230 231 error: ;给出错误提示(输入不规范) 232 lea dx,err 233 mov ah,9 234 int 21h 235 enterline 236 237 jmp begin ;如出错则返回起始点重新输入 238 239 yichu: ;超过500范围的提示 240 lea dx,out1 241 mov ah,9 242 int 21h 243 enterline 244 245 jmp begin ;如出错则返回起始点重新输入 246 247 stop: 248 MOV AH,4CH 249 INT 21H 250 251 judge PROC ;判断位数的子程序 252 xor ax,ax 253 xor dx,dx 254 xor bx,bx 255 xor cx,cx 256 mov cx,1 ;最初长度赋值为1 257 258 mov ax,si ;将检测的数赋值给ax 259 mov bx,10 ;除数赋值10 260 div bx 261 cmp ax,0 ;商等于0就跳转,去判断回文数 262 je judgeovr 263 mov cx,2 264 265 xor dx,dx 266 mov ax,si ;将检测的数赋值给ax 267 mov bx,100 ;除数赋值10 268 div bx 269 cmp ax,0 ;商等于0就跳转,去判断回文数 270 je judgeovr 271 272 mov cx,3 ;表明当前为数应该为三 273 jmp judgeovr ;去判断回文数 274 275 EXIT: 276 RET 277 judge ENDP 278 279 ascii_num PROC ;将字符串转成数字的子程序 280 281 mov cl,buf+1 ;获取实际键入字符数,置于CX寄存器中 282 xor ch,ch ;ch清0 283 284 xor di,di ;累加器清0 285 xor dx,dx ;dX寄存器清0 286 mov bx,1 ;由于从个位数开始算起,因而将所乘权值设为1 287 288 lea si,buf+2 ;将si指向接收到的第1个字符位置 289 add si,cx ;因为从个位算起,所以将si指向最后1个接收到的个位数 290 dec si ;往回减1使其指向字串最后一个元素 291 292 cov:mov al,[si] ;取出个位数给al 293 cmp al,'0' ;边界检查:如果输入不是0-9的数字,就报错 294 jb error 295 cmp al,'9' 296 ja error 297 298 sub al,30h ;将al中的ascii码转为数字 299 xor ah,ah 300 mul bx ;乘以所处数位的权值 301 cmp dx,0 ;判断结果是否超出16位数范围,如超出则报错 302 jne error 303 304 add di,ax ;将形成的数值放在累加器di中 305 jc error ;如数值超过16位数范围报错 306 307 cmp di,500 ;超过500的判断 308 ja yichu 309 310 mov ax,bx ;将BX中的数位权值乘以10 311 mov bx,10 312 mul bx 313 mov bx,ax 314 315 dec si ;si指针减1,指向前一数位 316 loop cov ;按CX中的字符个数计数循环 317 318 mov sum,di ;将最终转换结果从di中放置到sum中 319 EXIT: 320 RET 321 ascii_num ENDP 322 323 CODES ENDS 324 END START