取餘與位運算

2021-06-23 00:00:22 字數 1483 閱讀 9205

在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陣列容量的定義中,要求容量必須為...