经典的取绝对值方式
cdq
xor eax, edx ;edx=0 xor 0值不变 edx=1 xor 1就是取反
sub eax, edx ;edx=0 sub 0值不变 edx=1 sub -1就是加1,如果被除数是负数则是取反加1,那就是取绝对值了
取模优化
有符号
带幂优化
优化思路有两种
第一种带分支的:就是余数<除数 而除数是2的幂,所以余数是多少可以看二进制的末尾几位是多少那余数就是多少
如 10/4===0000 1010/4 因为除数是4所以直接后面的两位就是余数,同理除数是8取后面的3位就可以了
因为是有符号数,所以要考虑符号位的情况,还有取模0的情况
第二种不带分支的:直接利用取绝对值的方式后进行取余数,然后再根据取绝对值的方式(取反+1)来改变余数的正负,余数的正负是根据被除数来决定的
int main(int argc)
{
//第一种优化方式
printf("%d\n", argc % 2);
/*
mov eax,dword ptr [argc]
and eax,80000001h ;因为是除以2的幂,所以取位数(位数又除数来决定是多少位)就知道余多少,例如10/4,看10的二进制最后二位是多少,那就是余数
jns main+2Dh (0F513EDh) ;如果符号位S不为1(正数),就跳转,下面条件是处理负数的,改变负数的符号位和0的特殊情况
dec eax ;处理负数取模为0的指令 -1后全f,如果取模不为0的情况是不需要dec和inc指令的
or eax,0FFFFFFFEh ;负数的符号位
inc eax ;处理负数取模为0的指令 全f后+1就是0了,溢出
mov esi,esp 0F513ED-END
push eax
push 0F55858h
call dword ptr ds:[0F59114h]
*/
}
int main(int argc)
{
//第二种优化方式
printf("%d\n", argc % -2);
/*
mov eax, dword ptr[argc]
cdq
xor eax, edx ;edx=0 xor 0值不变 edx=1 xor 1就是取反
sub eax, edx ;edx=0 sub 0值不变 edx=1 sub -1就是加1,如果被除数是负数则是取反加1,那就是取绝对值了
and eax, 1 ;取余数
xor eax, edx ;对余数一次取反加1,正数不变,这就要看被除数是正还是负了,被除数是正,余数就为正
sub eax, edx
push eax
push 11D0DC4h
*/
}
不带幂的优化
思路就是用公式 余数=被除数-商*除数
int main(int argc)
{
printf("%d", argc % 7);
/*
mov esi, dword ptr[argc]
mov eax, 92492493h //magicNumber为正
imul esi
add edx, esi
sar edx, 2
mov eax, edx
shr eax, 1Fh
add eax, edx 利用除法得到商
lea ecx, [eax * 8] 商*(除数+1)就多了一个商
sub ecx, eax 减去一个商就是原来的 商*除数
mov eax, esi
sub eax, ecx 被除数-商*除数=余数
push eax
push 12B0DC4h
call printf(012A106Fh)
*/
}