4.15 EAX符号扩展到EDX
IA-32处理器的指令CDQ将EAX符号扩展到EDX。假若没有该指令,编程实现该指令功能。
(1)按照符号扩展的含义编程,即:EAX最高为0,则EDX=0;EAX最高为1,则EDX=FFFFFFFFH。
程序代码:
include io32.inc
.data
plmsg byte 'Input Number:' ,13,10,0
.code
start: mov eax,offset plmsg
call dispmsg
call readhd
test eax, 80000000h ;测试最高位
jz next ;最高位为0,跳转
mov edx,0ffffffffh
jmp done
next: mov edx,0
done : call dispcrlf
mov eax,edx
call disphd
exit 0
end start
运行结果:
(2)使用移位等指令进行优化编程。
法一:
解题思路:算数右移31位直接将符号位复制31次:
mov edx,eax sar edx,31 ;算数右移31位相当于将eax最高位复制31次
程序代码:
include io32.inc
.data
plmsg byte 'Input Number:' ,13,10,0
.code
start: mov eax,offset plmsg
call dispmsg
call readhd
mov edx,eax
sar edx,31 ;算数右移31位相当于将eax最高位复制31次
done : call dispcrlf
mov eax,edx
call disphd
exit 0
end start
运行结果:
法二:
解题思路:将eax最高位移出来给edx,edx再复制32次:
程序代码:
include io32.inc
.data
plmsg byte 'Input Number:' ,13,10,0
.code
start: mov eax,offset plmsg
call dispmsg
call readhd
mov edx,eax
rol eax,1 ;将eax最高位移出至CF
rcl edx,1 ;将最低位移出,CF进入最高位
sar edx,31 ;将此时的最高位复制31次
rcr eax,1 ;将CF中储存的数据归还给eax
done : call dispcrlf
call disphd
exit 0
end start
运行结果:
4.17 输入输出0~9数字
编写一个程序,先提示输入数字“Input Number:0~9”,然后在下一行显示输入的数字,结束;如果不是键入了0~9数字,就提示错误“Error!”,继续等待输入数字。
解题思路:分支结构比较一下即可:
程序代码:
include io32.inc
.data
plmsg byte 'Input Number:0~9:',13,10,0 ;输入提示信息
ermsg byte 'Error!',13,10,0 ;错误信息
.code
mov eax, offset plmsg
call dispmsg
start: call readuib ;输入一个无符号8位十进制数
cmp eax,0 ;和0比较
jb no ;小于0,跳转
cmp eax,9 ;和9比较
ja no ;大于9,跳转
jmp done
no: mov eax, offset ermsg
call dispmsg
jmp start ;继续输入
done: exit 0
end start
运行结果:
4.29 素数判断程序
编写一个程序,提示用户输入一个数字,然后显示信息说明该数字是否是素数。素数(Prime)是只能被自身和1整除的自然数。
解题思路:循环加分支,注意每步除法前eax要归值,edx要归零
程序代码:
(1)采用直接简单的算法:假设输入N,将其逐个除以2~N-1,只要能整除(余数为0)说明不是素数,只有都不能整除才是素数。
include io32.inc
.data
plmsg byte 'Input an integer:' ,13,10,0
findmsg byte 'Prime : ',0
nomsg byte 'Prime not!',13,10,0
errmsg byte 'Input Error!',0
.code
start: mov eax,offset plmsg
call dispmsg
call readuid
cmp eax,0
jz err ;输入值等于0,error
cmp eax,3 ;分支结构解决输入为1和2的情况
jb prime
mov ecx,eax ;初始化循环起始值
mov ebx,eax ;定义被除数
dec ecx
again:
mov edx,0
mov eax,ebx ;复原eax
div ecx ;edx.eax / ecx
test edx,edx ;edx 存余数,eax存商
jz noprime ;余数若为0,该数不是素数,跳转
dec ecx ;ecx自减
cmp ecx,1
jz prime ;循环正常结束,该数是素数
jmp again ;持续遍历至整数2,停止
prime:
mov eax, offset findmsg
call dispmsg
mov eax,ebx
call dispuid ;显示该素数
jmp done
noprime: mov eax, offset nomsg
call dispmsg
jmp done
err: mov eax, offset errmsg
call dispmsg
done: exit 0
end start
运行结果:
(2)采用只对奇数整除的算法:1、2和3是素数,所有大于3的偶数不是素数,从5开始的数字只要除以从3开始的奇数,只有都不能整除才是素数。
解题思路:利用分支结构,先判断1,2,3的情况,后判断大于3的偶数的情况,再判断大于3的奇数的情况,注意div之前edx要清零,eax要还原。
程序代码:
include io32.inc
.data
plmsg byte 'Input an integer:' ,13,10,0
findmsg byte 'Prime : ',0
nomsg byte 'Prime not!',13,10,0
errmsg byte 'Input Error!',0
.code
start: mov eax,offset plmsg
call dispmsg
call readuid
cmp eax,0
jz err ;输入值等于0,error
cmp eax,4 ;1,2,3都是素数
jb prime
mov edx,0
mov ebx,eax
shr ebx,1 ;右移除以2看余数
jnc noprime ;余数若为0,为偶数,该数不是素数,跳转
mov ecx,3 ;初始化循环起始值
mov ebx,eax ;定义被除数
again:
mov edx,0
mov eax,ebx ;复原eax
div ecx ;edx.eax / ecx
test edx,edx ;edx 存余数,eax存商
jz noprime ;余数若为0,该数不是素数,跳转
add ecx,2 ;ecx自增2,从3开始的奇数
cmp ecx,ebx
jz prime ;循环正常结束,该数是素数
jmp again ;持续遍历至整数2,停止
prime:
mov eax, offset findmsg
call dispmsg
mov eax,ebx
call dispuid ;显示该素数
jmp done
noprime: mov eax, offset nomsg
call dispmsg
jmp done
err: mov eax, offset errmsg
call dispmsg
done: exit 0
end start
运行结果: