由于除法优化实在太多了,所以这一篇继续讲,前面一篇说了除数为正数情况(常量),那么这篇就来说一说除数为负数的情况。首先里面涉及的很多基础知识请翻上一篇查看,其实如果理解了上一篇的那些基本原理,除法为负的情况也是很好理解的,因为除数为负的情况都是在除数为正的情况之上做了一点点的变化。
首先还是先来分一下情况
除数为常量-除数为负数情况
1.被除数无符号情况
2.被除数有符号情况
2.1 除数为2的幂
2.2 除数为非2的幂
2.2.1 Magic Number值为负的情况
2.2.2 Magic Number值为正的情况
这里细分的情况与前一篇略有不同,前一篇是先以是否为2的幂,然后再区分有无符号的问题。而在这篇博客中,是以有无符号先来区分的,为什么呢,下面来看一下第一种情况,说完就知道为什么要这样分了。
第一种情况是被除数是无符号的情况,注意我们这篇讨论的是被除数为负的情况,那么在上一篇中有说过这么一个知识点
除法有无符号混合为无符号除法(DIV)
也就是说无符号除以一个负数,不管这个负数是什么,最终都会以无符号来处理,编译器使用无符号除法(DIV),此时会把这个负数当成一个正数处理(将负数的补码当成无符号来处理)。那么一旦转为正数,本质上来说被除数无符号这种情况就不用讨论了,其可以转化为上一篇的正数情况(情况1和情况3)。当然我们下面还是需要验证下,是否真的和一样。
int main(unsigned int argc, char* argv[])
{
printf("%d",argc/-2);
printf("%d",argc/-4);
printf("%d",argc/-3);
printf("%d",argc/-7);
printf("%d",argc/4294967289); //4294967289 == -7
return 0;
}
我们主要来分析下release版下的汇编,因为debug下直接根据指令还原即可
mov esi,[esp+4+argc]
mov eax,esi
xor edx,edx
mov ecx,0FFFFFFFEh //-2
div ecx
mov eax,esi
xor edx,edx
mov ecx,0FFFFFFFCh //-4
div ecx
// 按照 3.1 还原
mov eax,40000001