基礎位運算基本原理和應用

微信公眾號

基礎位運算基本原理和應用
位運算是編程語言的基礎,在看源碼的時候會看到很多位運算代碼,但是在項目代碼中很少會看到位運算。因為應用代碼中,有很多判斷和計算都可以直接用數(shù)值的判斷和計算完成,沒有必要去用位運算,以至于這些基礎的東西慢慢用的越來越少,慢慢也就忘了。導致的一個結(jié)果就是看源代碼很費力,因為大量的位運算邏輯,看不懂。
作為程序員感覺數(shù)據(jù)位運算是非常必要,有點如下:

海拉爾ssl適用于網(wǎng)站、小程序/APP、API接口等需要進行數(shù)據(jù)傳輸應用場景,ssl證書未來市場廣闊!成為創(chuàng)新互聯(lián)的ssl證書銷售渠道,可以享受市場價格4-6折優(yōu)惠!如果有意向歡迎電話聯(lián)系或者加微信:028-86922220(備注:SSL證書合作)期待與您的合作!

  • 看源碼時能夠更好的理解
  • 位運算更接近計算機的習慣,執(zhí)行的效率會更高
  • 裝逼利器,在項目中使用位運算,體現(xiàn)逼格

N種基本的位運算

位運算 -- 與運算符(&)

運算規(guī)則:

操作數(shù)10011
操作數(shù)2 0 1 0 1
與運算 0 0 0 1

規(guī)則總結(jié):只有兩個操作數(shù)都是1的時候運算結(jié)果才為1,其他都是0。換句話說就是只要包含0就是0。

運算如下:

基礎位運算基本原理和應用

位運算 -- 或運算符(|)

運算規(guī)則:

操作數(shù)10011
操作數(shù)2 0 1 0 1
或運算 0 1 1 1

規(guī)則總結(jié):只有兩個操作數(shù)都是0的時候運算結(jié)果才為0,其他都是1。換句話說就是只要包含1就是1。

運算如下:

基礎位運算基本原理和應用

位運算 -- 非運算符(~)

運算規(guī)則:

操作數(shù)10
或運算 0 1

規(guī)則總結(jié):取反操作,1變0,0變1。

位運算 -- 異或運算符(^)

運算規(guī)則:

操作數(shù)10011
操作數(shù)2 0 1 0 1
或運算 0 1 1 0

規(guī)則總結(jié):操作數(shù)相同,運算結(jié)果就是0,反之操作數(shù)不同就為1。
基礎位運算基本原理和應用

位運算 -- 有符號位移運算符(>>,<<)

在二進制里面總共有32位,0-31,第31位是表示當前數(shù)值的正負,當時0的時候表示這個數(shù)值是正數(shù),當是1表示這個數(shù)值是負數(shù)。

正數(shù)左移(<<)

以2<<2為例。
2:00000000 00000000 00000000 00000010
向左移動兩位,右側(cè)會空出來兩個位置,兩個位置用0補位得到的結(jié)果如下:
8:00000000 00000000 00000000 00001000
轉(zhuǎn)換成十進制對應的數(shù)值為8。因此可以得到2<<2的結(jié)果是8。

負數(shù)左移(<<)

以-2<<2為例。
-2:11111111 11111111 11111111 11111110
向左移動兩位,右側(cè)空出的兩個位置用0補位,到這里還沒有結(jié)束,要是想計算出它的值,還要做補位,那就是將當前移位得到的結(jié)果(11111111 11111111 11111111 11111000)減一后再取反碼,得的結(jié)果就是補碼的結(jié)果。
減一操作:
11111111 11111111 11111111 11110111
取反碼的結(jié)果:
00000000 00000000 00000000 00001000
這個對應的值是8,因為是負值,那么得到的結(jié)果就是-8,因此-2<<2的結(jié)果是-8。

左移總結(jié)

這里可以看出來,在左移的時候,不論這個目標值(2或-2)是正數(shù)還是負數(shù),結(jié)果都符合一個規(guī)律,即表達式:$m*2^n$。m表示目標值,n表示的是移位的位數(shù)。
-2<<2 = -8,2<<2 = 8,同理可以得到2<<4 = 2x2^4 = 32,-2<<4 = -2x2^4 = -32。

正數(shù)右移(>>)

以10>>2為例。
10:00000000 00000000 00000000 00001010
右移兩位,右側(cè)的10就會被舍棄,左側(cè)會空出兩個空位,空位用符號位補齊,前面說過正數(shù)的符號位是0,也就是用0補齊,得到的結(jié)果如下:
2:00000000 00000000 00000000 00000010
得到的十進制結(jié)果是2,結(jié)論就是10>>2=2。

負數(shù)右移(>>)

以-10>>2為例。
-10:11111111 11111111 11111111 11110110
同樣是右移,溢出的部分舍棄,空位的部分用符號位補齊,得到的結(jié)果如下:
11111111 11111111 11111111 11111101
減一操作后結(jié)果:
11111111 11111111 11111111 11111100
取反碼后的結(jié)果:
00000000 00000000 00000000 00000011
對應的十進制結(jié)果是3,因為是負數(shù),那么結(jié)果就是-3。結(jié)論是-10>>2。

有符號位移總結(jié)

整體的總結(jié)來看,正數(shù)的左移和右移沒有什么問題,但是負數(shù)存在一個補碼的問題,比較麻煩。補碼記住一個口訣就可以,移位、補碼、減一、取反碼,得到正數(shù)結(jié)果加個負號。這樣就可以得到正確結(jié)果。

位運算 -- 無符號位移運算符(>>>)

Java中沒有無符號左移的說法,這里只說右移。同樣也是分正數(shù)和負數(shù)來講。

正數(shù)右移(>>>)

以10>>>2為例。
10:00000000 00000000 00000000 00001010
右移后,左側(cè)空出的位置用0補齊,但是這里需要注意的是這個0并不是指符號位,只是一個普通的補位。得到的結(jié)果如下:
2:00000000 00000000 00000000 00000010
得到的十進制結(jié)果是2,結(jié)論就是10>>2=2。這個和有符號位移是得到相同的結(jié)果。

負數(shù)右移(>>>)

以-10>>>2為例。
-10:11111111 11111111 11111111 11110110
右移后,左側(cè)空位用0補,注意不是用1補,后面說原因。
00111111 11111111 11111111 11111101
這個結(jié)果就很大了,結(jié)果是1073741821,負數(shù)變成了這么大的負數(shù),不要懷疑自己的眼神,這個結(jié)果是正確的。

總結(jié)

所謂的無符號右移,就是將原有的二進制值直接右移得到結(jié)果,不論是負數(shù)還是正數(shù),沒有補碼的操作,補位都統(tǒng)一使用0,而不是對應的符號位1或0。
到這里N種基本的位運算已經(jīng)說明結(jié)束,接下來看幾個例子,和在代碼中常用的一些技巧。

常用位運算使用
  • 判斷一個數(shù)是奇數(shù)還是偶數(shù)。
    // true表示為奇數(shù),false表示為偶數(shù)
    public boolean checkNum(int num){
    return (num&1) == 1;
    }

    1的二進制是00000000 00000000 00000000 00000001,&運算的規(guī)則是只有都是1,結(jié)果才是1,很明顯,不管是什么數(shù),和1進行&運算,前31位都是0,只有最后一位可能得出不同的結(jié)果。偶數(shù)最后一位肯定是0,奇數(shù)肯定是1,那么結(jié)果就顯而易見了。

  • 不用中間變量,交換兩個數(shù)值(面試常見)
    // 傳入的a=3,b=5
    public void swap(int a,int b){
    a ^= b;// a = a^b;
    b ^= a;// b = b^a;
    a ^= b;// a = a^b;
    System.out.println("a="+a);
    System.out.println("b="+b);
    }
    /*
    輸出結(jié)果:
    a=5
    b=3
    */

    這個靈活的用到了異或來實現(xiàn)。下面做個簡單的說明。
    a = 3:00000011
    b = 5:00000101
    a異或b得到的結(jié)果是:00000110,這個結(jié)果賦值給a;
    b異或a得到的結(jié)果是:00000011,這個結(jié)果賦值給b;
    a異或b得到的結(jié)果是:00000101,這個結(jié)果賦值給a;
    所以最終得到的結(jié)果是:
    a = 5:00000101
    b = 3:00000011

  • 取絕對值
    public int getAbs(int n){
    return (n ^ (n >> 31)) - (n >> 31);
    }

    具體不說,可以自己嘗試著寫一下。(因為涉及到正數(shù)、負數(shù)的舉例,然后負數(shù)又有補碼操作,要寫的內(nèi)容太多,本博主就傲嬌一下,不寫啦!)
    其實這里的例子很多,就不都去說了,有興趣的可以度娘一下相關(guān)的博客,有很多文章。

實際項目經(jīng)驗操作

涉及到公司的東西,這里不會寫的很具體,給思路。

現(xiàn)在有一個訂單,訂單可以進行很多操作,如:創(chuàng)建、修改、退單、接單、終止、派單、提交完成等操作。同時訂單也有很多狀態(tài),如:待接單、進行中、已終止、已完成等狀態(tài)?,F(xiàn)在的場景就是不同的狀態(tài)對應的操作是不一樣的,前端需要根據(jù)不同的狀態(tài)顯示不同的操作控件。

思路一:

最簡單也是最麻煩的,用N個flag字段表示可進行的操作,返回數(shù)據(jù)的時候?qū)γ總€flag字段賦值true、false,表示是否能夠進行此操作。但是這樣存在一個巨大的問題,當后期有一個操作去掉了或者添加了幾種新的操作,這個時候就涉及到字段的刪除和新增,改動較大,可維護性差,不夠靈活。

思路二:(推薦)

使用此二進制的方式表示。實現(xiàn)如下:

第一位:0,1表示是否可以修改

第二位:0,1表示是否可以接單

第三位:0,1表示是否可以終止

返回給前端只要一個字段tags,如對應的值是:010,那就表示不可以修改、可以接單、不可以終止。

如果現(xiàn)在終止操作不要了,那么這個二進制位始終給0就可以。如果新增了一個提交操作,那就讓第四位表示是否可以提交。這樣不需要添加字段,只要在原字段加一位就OK。

另外還有其他很多應用場景。

本文名稱:基礎位運算基本原理和應用
文章地址:http://bm7419.com/article40/pcegeo.html

成都網(wǎng)站建設公司_創(chuàng)新互聯(lián),為您提供域名注冊Google、網(wǎng)站制作營銷型網(wǎng)站建設、建站公司、企業(yè)建站

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

成都網(wǎng)站建設