在c風格語言中(比如c,c++,c# (注:排名按出生日期 ^_^)),取餘運算子定義為「%」。但在很久很久以前,cpu採用如下方法計算餘數(注意,該方法
只對2的n次方數系有效):
x & (2^n - 1)
首先從求餘數談起,我們知道,計算機中儲存的方式是0和1序列:
1 0001 2^0
2 0010 2^1
3 0011 2^1 + 1
4 0100 2^2
當我們把這些數字序列左移一位的時候... 是的,你答對了,相當與數字擴大為原來的2倍,同理可知右移一位就是縮小為原來的1/2。
那麼餘數在**?被移掉的那些位便是餘數,這是無數前人的證明結果~可以自己拿筆和紙畫一畫就明白了。
那麼,說了這麼多,為什麼乙個求餘的%被替換為:x & (2^n - 1)?
舉例:9 的二進位制就是1001
8 的二進位制就是1000
顯然餘數是1,按照公式這麼做:
把8的二進位制1000換為8-1也就是7,7的二進位制表示為:0111
1001&0111 = 0001
答案為1與我們想的結果一致。
我們把9換成13,過程你親自來一遍,結果在你沒算錯的情況下必然和我的一樣:0101
但是注意,這種方法只是適合於求乙個數除以二的n次冥才正確。
先說原理再說疑問:
原理:由於除數是2^n (n為0起始遞增的整數),所以隱藏條件就是,除數的2進製真身只能是如下的方式展現:
0001,0010,0100,1000.。。。。。
沒看出來?那我們繼續:
10000,100000,1000000.。。。。
明白了吧,
當我們求餘的時候,相當於除以2的n次冥,也就是相當於把數本身右移n位
,但是移走的那些餘數可一去不復返了。(什麼?你說在cf暫存器中?嗯,這是個好注意,也許有另種一實現?!)。有什麼辦法保護這些即將失去的資料呢?
我們把上面的數字減一就發現:
0000,0001,0011,0111,01111,011111,0111111.。。。。。。
如您所見,當和1做位運算時候,得到的結果是那個數的本身。前面例子1001&0111= 0001相當於1001右移三位得到0001,那麼(13)1101右移三位還是0001,這2個0001表示的是商,兩個移走的餘數分別是「001」和「101」,發現特徵了嚒?除以2的n次方就是要儲存被除數即將被移走的低n位。
好了,我知道上面我講的可能不清楚,但是下面才是真正驚險的地方:
2^3=8 然後8表示為1000 有3個零,預示著右移位數,右移位數告訴我們被除數即將被移走幾位,我們如果將這幾位與1按位運算不就能知道這幾位到底是0還是1,也就是能完全儲存到移走的資料,它就是我們期望的餘數。
嗯,我確信看完我的解釋你還在暈眩之中,別管他們,該幹嘛幹嘛,睡完一覺之後我想我的這些話也許會被你的大腦自動解析,你最終也會明白這是怎麼一回事。
嗯,我想說,如果早起電腦都這麼做的話,那麼求乙個非2的n次冥的取餘怎麼來實現呢?
取餘與位運算
在c風格語言中 比如c,c c 注 排名按出生日期 取餘運算子定義為 但在很久很久以前,cpu採用如下方法計算餘數 注意,該方法只對2的n次方數系有效 x 2 n 1 首先從求餘數談起,我們知道,計算機中儲存的方式是0和1序列 1 0001 2 0 2 0010 2 1 3 0011 2 1 1 4...
取餘與位運算
在c風格語言中 比如c,c c 注 排名按出生日期 取餘運算子定義為 但在很久很久以前,cpu採用如下方法計算餘數 注意,該方法只對2的n次方數系有效 x 2 n 1 首先從求餘數談起,我們知道,計算機中儲存的方式是0和1序列 1 0001 2 0 2 0010 2 1 3 0011 2 1 1 4...
基礎 位與運算與取餘
關於位與運算 與取餘 今天在研究hashmap原始碼的時候,發現其原始碼中在解決entry分布時,本來大多數人以為會用index hash length,但是原始碼中卻使用了index hash lenth 1 的方式。另外由上述還可以注意到,在原始碼中對於entry陣列容量的定義中,要求容量必須為...