2的幂取模优化
若被除数是正数,只需取低k位的值即可。
eg. 若k取3,则除数为8,被除数为9,则模数为9的低3位,001(2)
可以这样做的原因是第k+1位的值等于2k,也就是说大于等于k+1位的值都大于\(2^k\),他们的取值不影响余数
余数的取值范围为 \([0,2^k-1]\)
若被除数是负数,取低k位的值,还要将k位前的高位补1。
eg. 若k取3,则除数为8,被除数为-9,则模数为-9的低3位,111(2),将高位补1为\(FFFFFFFF = -1\)
由于余数的取值范围为\([-2^k,-1],当余数为2^k时,其实真正的余数应当为0\)
eg. 若k取3,则除数为8,被除数为-8,则模数为-8的低3位,000(2),将高位补1为\(FFFFFFF8 = -8\)
那么如何将-2^k,变为0呢,编译器用了一个非常巧妙的办法,就是先减1,再在高位补1,再加1。
eg. 若k取3,则除数为8,被除数为-8,则模数为-8的低3位,000(2),先减1,得111将高位补1为\(FFFFFFFF\),再加1,得0
其他的余数取值,由于减1加1没有影响高位,所以加减相互抵消,不会影响最终的取值
看看实际的汇编代码
//当eax为-8时,
and eax,80000007 //eax=80000000
//由于eax<0,
执行dec eax //eax = 7FFFFFFF
or eax,FFFFFFF8 //eax = FFFFFFFF
inc eax //eax = 00000000