做者:泥沙磚瓦漿木匠
我的簽名:打算起手不凡寫出鴻篇巨做的人,每每堅持不了完成第一章節。 算法
若是個人幫到了你,是否樂意捐助一下或請一杯啤酒也好呢?有你支持,乾的更好~ 編程
點這參與衆籌 個人支付寶:13958686678 安全
自從上篇[Java 泥水匠] Java Components 之一:Java String (確定有你不懂的泥瓦匠很快又和大家聊起來了。寫的還不錯~ 網絡
要時刻對本身說: 學習
回到正題,今天是講位運算的,確定有你不知道的。
提綱: 測試
看題目顧名思義,泥瓦匠要跟大家聊聊這位運算。怎麼聊法,依舊和老套。師傅出招棋盤上馬,你徒弟怎麼對答,而後周而復始。你就青出於藍了。很早的時候在一本《算法競賽入門經典》,有些acmer應該知道的。原題目很簡單,是這樣的:
兩個變量A,B如何交換。
「泥瓦匠,你找抽。定個temp不就搞定了。」罵聲將至,我趕忙說,除了這個方法,還有下面這個:
編碼
1
2
3
4
5
6
|
<font size="4" face="宋體">A = A + B;
B = A –B;
A = A - B;
</font>
|
這樣子,咱們不可全盤否定,在多數狀況下,仍是能達到目的的。可是問題就來了,這樣作爲何不行呢。咱們考慮下,一個是這試用的範圍很小,不知足所有類型數據。二個是這個會越界,越界致使咱們算法和程序會bug或者沒法進行。
又看看題目,聰明的小夥伴興許想到了: 加密
1
2
3
4
5
6
7
8
|
<font size="4" face="宋體">private static void test1()
{
int A = 11;
int B = 222;
A = A ^ B;
B = A ^ B;
A = A ^ B;
}</font>
|
異或運算,是按照二進制位進行。異或運算的規則是0⊕0=0,0⊕1=1,1⊕0=1,1⊕1=0。「泥瓦匠,這個也太煩了吧,記公式我最不行了。」別怕,泥瓦匠有高招。這個也是來自前人,古人的武功祕籍。不是嗎什麼易筋經,什麼少林武學。哈哈,太極啊,書法啊,要那個靈性,技巧。哈哈,泥瓦匠喜歡書法,喜歡的能夠交流。
記憶宮殿:異或異或,又稱半加法運算。例如,1⊕1能夠當成二進下,1+1=10而後取最後一位,正好是異或的結果,0+0、1+一、0+1同理。這只是前人流傳下來的記憶方法。 spa
泥瓦匠就在補充個例子,利用抑或算法進行加密解密。這是種簡單加密,可是也有它的優點:速度快,長數據的通常加密任務很適合。很少說,代碼以下: .net
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
/* encrypt using the exclusive or*/
private static void test2(String str)
{
byte key = 123;
byte strByte[] = str.getBytes();
/* encrypt */
for (int i = 0; i < strByte.length; i++)
{
strByte[i] = (byte) (strByte[i] ^ key);
}
System.out.println("加密後:" + new String(strByte));
/* decrypt */
for (int i = 0; i < strByte.length; i++)
{
strByte[i] = (byte) (strByte[i] ^ key);
}
System.out.println("解密後:" + new String(strByte));
}
|
咱們測試下 test2("13958686678");,而後在控制檯能夠清楚的看出加密後和解密後的狀態:
總結:加密解密的操做方式同樣,這個加密不怎麼棒,並且一看數據都是對應的AABBCC型。但加密後的數據也能夠進行存儲或網絡傳輸。若是有不須要很大安全性的,可是數據有長要求速度和效率的能夠嘗試下哦
下面泥瓦匠要講這個&了。上面講了異或,下面我就講講這個,在很人眼裏彷彿和異或有着某種,或是對立或是啥的關係的按位與運算符。其實沒有,他們只是在CPU級別的,一些門電路設計下的規律而已。哈哈,雖然學過電子技術,但常常逃課,還掛科了,泥瓦匠也就不顯擺我電子技術多牛逼了。舉個例子吧:
1
2
3
4
5
6
|
private static void test3()
{
int a = 6550; // 1100110010110
a = a & 255; // 11111111
System.out.println(a);// 10010110
}
|
例子中,看了註釋有些人懂了。其實例子很簡單,就是一個數字截取二進制下從低到高的8位。和上面的同樣,這運算符普遍的運用在系統內部。效率極高,但咱們也能夠在某種算法中去。好比我如今想要6550的二進制的不要二進制下從低到高的8位,那樣你是否立刻就能寫出。只要把255改爲(65535 - 255),而後右移8位便可呢?爲何是這個兩個數字呢,泥瓦匠告訴你轉化成二進制你就明白了。
按位與運算與(AND):對兩個整型操做數中對應位執行布爾代數,兩個位都爲1時輸出1,不然0。
這也沒什麼記憶技巧,一與一,唱着歌謠記下去。
累了累了,先去玩一會,再看下面很枯燥的東西吧。我推薦番茄工做法。25分鐘。
下面泥瓦匠和大家一塊兒學習這個枯燥的東西。要學習原碼補碼運算。首先得知道一些基礎的東西:機器數和真值。所謂的機器數就是,一個數在計算機中的二進制形式。機器數時代符號的,在計算機用一個數的最高位存放符號。正數爲0,負數爲1。那什麼叫真值呢?真值其實就是實際值,由於最高位的0或者1會致使形式上的有變,就像 1000 0011 表示機器數,它的真值爲 –3 或者 -000 0001。哈哈?泥瓦匠這個太簡單的。對,什麼事情都是簡單到複雜。簡單的事情作多了就成大事了。
而原碼, 反碼, 補碼是機器存儲一個具體數字的編碼方式。下面簡單介紹這三個:
原碼是人最容易理解和計算的表達式。第一位表示符號,後面的表示值。0爲正值,1爲負值。
反碼,顧名思義,和原碼有關係。有時候,一個反碼錶示負數,咱們沒法將其計算。能夠轉換爲原碼在計算。反碼的計算方法以下:
正數的反碼是其自己
負數的反碼是在其原碼的基礎上, 符號位不變,其他各個位取反.
補碼的表達方式也以下:
正數的補碼就是其自己
負數的補碼是在其原碼的基礎上, 符號位不變, 其他各位取反, 最後+1. (即在反碼的基礎上+1)
「我去,泥瓦匠,頭暈了。哈哈累了累了。慢慢來」
爲何要用這些呢。個人建議先死背,而後用領會。由於計算機裏面最基礎的運算須要他們幫助計算機完成。由於一個符號位正負會讓基礎電路設計很複雜。因此就想出來用符號位參與運算。反碼,補碼是用來計算用的。下面舉個簡單的例子。首先是反碼計算十進制的表達式: 1-1=0。下面摘自網絡大牛結論:
1 1 - 1 = 1 + (-1) = [0000 0001]原 + [1000 0001]原= [0000 0001]反 + [1111 1110]反 = [1111 1111]反 = [1000 0000]原 = -0
發現用反碼計算減法, 結果的真值部分是正確的. 而惟一的問題其實就出如今"0"這個特殊的數值上. 雖然人們理解上+0和-0是同樣的, 可是0帶符號是沒有任何意義的. 並且會有[0000 0000]原和[1000 0000]原兩個編碼表示0.
因而補碼的出現, 解決了0的符號以及兩個編碼的問題:
1 1-1 = 1 + (-1) = [0000 0001]原 + [1000 0001]原 = [0000 0001]補 + [1111 1111]補 = [0000 0000]補=[0000 0000]原
這樣0用[0000 0000]表示, 而之前出現問題的-0則不存在了.並且能夠用[1000 0000]表示-128:
1 (-1) + (-127) = [1000 0001]原 + [1111 1111]原 = [1111 1111]補 + [1000 0001]補 = [1000 0000]補
-1-127的結果應該是-128, 在用補碼運算的結果中, [1000 0000]補 就是-128. 可是注意由於其實是使用之前的-0的補碼來表示-128, 因此-128並無原碼和反碼錶示.(對-128的補碼錶示[1000 0000]補算出來的原碼是[0000 0000]原, 這是不正確的)
使用補碼, 不只僅修復了0的符號以及存在兩個編碼的問題, 並且還可以多表示一個最低數. 這就是爲何8位二進制, 使用原碼或反碼錶示的範圍爲[-127, +127], 而使用補碼錶示的範圍爲[-128, 127].
由於機器使用補碼, 因此對於編程中經常使用到的32位int類型, 能夠表示範圍是: [-231, 231-1] 由於第一位表示的是符號位.而使用補碼錶示時又能夠多保存一個最小值.
最後一個綜合性算法例子,泥瓦匠就結束這篇位運算的文章。泥瓦匠都口水講完了。看吧看吧,一塊兒看。
業務系統中,咱們會發現大量的斷定是否。以int數據爲例子,若是按照十進制的方式存儲數據,一個32位的int變量只能存儲一個數值,而若是使用二進制方式存儲數據(缺點是隻能存儲0或1兩個數據)則能夠存儲32個數據,將極大的節約內存。利用位運算存儲數據,主要是爲了減小程序佔用的內存。這樣的設計是沒有錯的,可是如何操做呢?哈哈,泥瓦匠也不賣關子了。固然是位運算。但有些同窗用什麼toBinary轉來轉去,都不知道這樣的操做複雜度很高,致使得不償失。
例如,在一個int變量的從右側開始倒數第5位存儲數據,則存儲和讀取數據的代碼以下所示:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
private static void test4()
{
//在一個int變量的從右側開始倒數第5位存儲數據
int bData = 0;
bData = bData | (1 << (5 - 1)); //存儲數值1
System.out.println(bData);
bData = bData & (~(1 << (5 - 1))); //存儲數值0
System.out.println(bData);
int n = bData & (1 << (5 - 1)); //讀取數據
System.out.println(n);
}
|
例子能夠看出,咱們成功的把5位的1和0互換。這就表明着一個是否的是否狀態。因此泥瓦匠想說的是,考慮int的位而不是表面的意義能創造更多財富。財富來源於細節。和武學同樣,最高境界就是 無形。可是要從有形來,組合的有形深不可測。就像這個綜合案例同樣。
精髓:掌握到底層的妙用,方能成就高層建築。
組合拳的組合的有形深不可測。就像這個綜合案例同樣。
仍是那句話,泥瓦匠想說:
如以上文章或連接對你有幫助的話,別忘了在文章按鈕或到頁面右下角點擊 「贊一個」 按鈕哦。你也能夠點擊頁面右邊「分享」懸浮按鈕哦,讓更多的人閱讀這篇文章