一. 模运算
1. 无符号
1.1 对2的幂取模
printf("%d", argc % 8); //无符号数argc
mov eax,dword ptr [argc]
and eax,7 ; argc & (2^n - 1)
push eax
push offset string "%d"
call printf
add esp,8
判断一个数是否为2的倍数,可以用nNum & 1计算,
判断一个数是否为4的倍数,可以用nNum & 3计算,
判断一个数是否为8的倍数,可以用nNum & 7计算,
判断一个数是否为16的倍数,可以用nNum & 15计算,
判断一个数是否为2^n的倍数,可以用nNum & (2^n - 1)计算,结果为0说明是2^n的倍数。再推进一步,nNum % 2^n等于nNum & (2^n - 1)。
1.2 对非2的幂取模
printf("%d", argc % 7); //无符号数argc
mov esi,dword ptr [argc]
mov eax,24924925h
mul eax,esi
mov ecx,esi
sub ecx,edx
shr ecx,1
add ecx,edx
shr ecx,2 ;乘减移加移,magic高位补1. ecx = esi/7
lea eax,[ecx*8]
sub eax,ecx ;eax = ecx*7
sub esi,eax ;esi = esi - ecx*7. 被除数减去商和除数之积,得余数
push esi
push offset string "%d" (0D2100h)
call printf (0D1010h)
2. 有符号数
2.1 对2的幂取模
printf("%d", argc % 8);
mov eax,dword ptr [argc]
and eax,80000007h ; 类似无符号的算法,多了最高bit的符号位
jns main+12h ; 是正数则跳到 push eax这一行
dec eax ; 如果argc是8的负整数倍,这里变为7FFFFFFF
or eax,FFFFFFF8h ; 最后3bit是1,其余是0,相当于保留符号位
inc eax ;FFFFFFFF+1得到0
push eax
push offset string "%d"
call printf
VC6中对-(2^n)取模有无分支优化:
argc % -8
除数为负数时,模运算结果不受影响,和正数一致。
2.2 对非2的幂取模
printf("%d", argc % 7); //有符号数argc
mov esi,dword ptr [argc]
mov eax,92492493h
imul esi
add edx,esi
sar edx,2
mov ecx,edx
shr ecx,1Fh
add ecx,edx ; ecx = esi/7
lea eax,[ecx*8]
sub eax,ecx ; eax = ecx*7
sub esi,eax ; esi = esi - ecx*7. 被除数减商和除数之积,得余数
push esi
push offset string "%d" (01112100h)
call printf (01111010h)
二. 三目运算符
argc == 0 ? 0 : -1
mov eax, dword ptr [argc]
neg eax ;if argc=0 CF=0, else CF=1
sbb eax, eax ;if argc=0 eax=0-CF=0, else eax=0-CF=-1
return argc == 0 ? 10 : 5;
mov eax, dword ptr [argc]
neg eax
sbb eax, eax
and eax, -5
add eax, 10
return argc == 789 ? 50 : 100;
mov eax, [argc]
sub eax, 789
neg eax
sbb eax, eax
and eax, 50
add eax, 50
return argc > 789 ? 50 : 100;
xor eax, eax
mov ecx, [argc]
cmp ecx, 789
setle eax
dec eax
and eax, -50
add add, 100
return argc < 789 ? 20 : 80;
mov eax, 80
mov ecx, 20
cmp [argc], 789
cmovl eax, ecx
return argc < 789 ? argc+20 : argc+80;
mov eax, 20
mov ecx, 80
cmp [argc], 789
cmovge eax, ecx
add eax, [argc]