Java二進位和位運算,這一萬字準能餵飽你

2020-09-05 Java清風

作 者:BAT的烏託邦

原文連結:https://mp.weixin.qq.com/s/1jqe1-bCSSRchJ4SWykh9Q

本文就先行來認識認識Java中的位運算」。位運算在Java中很少被使用,那麼為何Jackson裡愛不釋手呢?一切就為兩字:「性能」/「高效」。用計算機能直接看懂的語言跟它打交道,你說快不快,不用多想嘛。

✍正文

提及位運算,對絕大多數Java程式設計師來說,是一種「既熟悉又陌生」的感覺。熟悉是因為你在學JavaSE時肯定學過,並且在看一些開源框架(特別是JDK源碼)時都能看到它的身影;陌生是因為大概率我們不會去使用它。當然,不能「流行」起來是有原因的:不好理解,不符合人類的思維,閱讀性差…...

小貼士:一般來說,程序讓人看懂遠比被機器看懂來得更重要些

位運算它在low-level的語言裡使用得比較多,但是對於Java這種高級語言它就很少被提及了。雖然我們使用得很少但Java也是支持的,畢竟很多時候使用位運算才是「最佳實踐」

位運算在日常開發中使用得較少,但是巧妙的使用位運算可以大量減少運行開銷,優化算法。「一條語句可能對代碼沒什麼影響,但是在高重複,大數據量的情況下將會節省很多開銷。」

二進位

在了解什麼是位運算之前,十分有必要先科普下二進位的概念。

二進位是計算技術中廣泛採用的一種數制。二進位數據是用0和1兩個數字來表示的數。它的基數為2,進位規則是「逢二進一」,借位規則是「借一當二」。因為它只使用0、1兩個數字符號,非常簡單方便,易於用電子方式實現。

小貼士:半導體開代表1,關代表0,這也就是CPU計算的最底層原理

先看一個例子:

求 1011(二進位)+ 11(二進位) 的和?結果為:1110(二進位)

二進位理解起來非常非常的簡單,比10進位簡單多了。你可能還會思考二進位怎麼和十進位互轉呢?畢竟1110這個也看不到啊。有或者往深了繼續思考:如何轉為八進位、十六進位、三十二進位......進位轉換並非本文所想講述的內容,請有興趣者自行度娘。

二進位與編碼

這個雖然和本文內容關聯繫並不是很大,但順帶撈一撈,畢竟編碼問題在開發中還是比較常見的。

計算機能識別的只有1和0,也就是二進位,1和0可以表達出全世界的「所有」文字和語言符號。那如何表達文字和符號呢?這就涉及到「字符編碼」了。字符編碼強行將每一個字符對應一個十進位數字(請注意字符和數字的區別,比如0字符對應的十進位數字是48),再將十進位數字轉換成計算機理解的二進位,而計算機讀到這些1和0之後就會顯示出對應的文字或符號。

  • 一般對「英文字符」而言,一個字節表示一個字符,但是對漢字而言,由於低位的編碼已經被使用(早期計算機並不支持中文,因此為了擴展支持,唯一的辦法就是採用更多的字節數)只好向高位擴展
  • 字符集編碼的範圍utf-8>gbk>iso-8859-1(latin1)>ascll。ascll編碼是美國標準信息交換碼的英文縮寫,包含了常用的字符,如阿拉伯數字,英文字母和一些列印符號共255個(一般說成共128個字符問題也不大)

UTF-8:一套以 8 位為一個編碼單位的「可變長」編碼,會將一個碼位(Unicode)編碼為1到4個字節(英文1位元組,大部分漢字3位元組)。

Java中的二進位

在Java7版本以前,Java是不支持直接書寫除十進位以外的其它進位字面量。但這在Java7以及以後版本就允許了:

  • 二進位:前置0b/0B
  • 八進位:前置0
  • 十進位:默認的,無需前置
  • 十六進位:前置0x/0X

@Testpublic void test1() {    //二進位    int i = 0B101;    System.out.println(i); //5    System.out.println(Integer.toBinaryString(i));    //八進位    i = 0101;    System.out.println(i); //65    System.out.println(Integer.toBinaryString(i));    //十進位    i = 101;    System.out.println(i); //101    System.out.println(Integer.toBinaryString(i));    //十六進位    i = 0x101;    System.out.println(i); //257    System.out.println(Integer.toBinaryString(i));}

結果程序,輸出:

51016510000011011100101257100000001

說明:System.out.println()會先自動轉為10進位後再輸出的;toBinaryString()表示轉換為二進位進行「字符串」進行輸出。

便捷的進位轉換API

JDK自1.0開始便提供了非常便捷的進位轉換的API,這在我們有需要時非常有用。

@Testpublic void test2() {    int i = 192;    System.out.println(&34;);    System.out.println(&34; + Integer.toBinaryString(i)); //11000000    System.out.println(&34; + Integer.toOctalString(i)); //300    System.out.println(&34; + Integer.toHexString(i)); //c0    System.out.println(&34;);    // 統一利用的為Integer的valueOf()方法,parseInt方法也是ok的    System.out.println(&34; + Integer.valueOf(&34;, 2).toString()); //192    System.out.println(&34; + Integer.valueOf(&34;, 8).toString()); //192    System.out.println(&34; + Integer.valueOf(&34;, 16).toString()); //192    System.out.println(&34;);}

運行程序,輸出:

---------------------------------十進位轉二進位:11000000十進位轉八進位:300十進位轉十六進位:c0---------------------------------二進位轉十進位:192八進位轉十進位:192十六進位轉十進位:192---------------------------------

如何證明Long是64位的?

我相信每個Javaer都知道Java中的Long類型佔8個字節(64位),那如何證明呢?

小貼士:這算是一道經典面試題,至少我提問過多次~

有個最簡單的方法:拿到Long類型的「最大值」,用2進位表示轉換成字符串看看長度就行了,代碼如下:

@Testpublic void test3() {    long l = 100L;    //如果不是最大值 前面都是0  輸出的時候就不會有那麼長了(所以下面使用最大/最小值示例)    System.out.println(Long.toBinaryString(l)); //1100100    System.out.println(Long.toBinaryString(l).length()); //7    System.out.println(&34;);    l = Long.MAX_VALUE; // 2的63次方 - 1    //正數長度為63為(首位為符號位,0代表正數,省略了所以長度是63)    //111111111111111111111111111111111111111111111111111111111111111    System.out.println(Long.toBinaryString(l));    System.out.println(Long.toBinaryString(l).length()); //63    System.out.println(&34;);    l = Long.MIN_VALUE; // -2的63次方    //負數長度為64位(首位為符號位,1代表負數)    //1000000000000000000000000000000000000000000000000000000000000000    System.out.println(Long.toBinaryString(l));    System.out.println(Long.toBinaryString(l).length()); //64}

運行程序,輸出:

11001007---------------------------------------11111111111111111111111111111111111111111111111111111111111111163---------------------------------------100000000000000000000000000000000000000000000000000000000000000064

說明:在計算機中,負數以其正值的「補碼」的形式表達。因此,用同樣的方法你可以自行證明Integer類型是32位的(佔4個字節)。

Java中的位運算

Java語言支持的位運算符還是非常多的,列出如下:

  • &:按位與
  • |:按位或
  • ~:按位非
  • ^:按位異或
  • <<:左位移運算符
  • >>:右位移運算符
  • >>>:無符號右移運算符

除~以 外,其餘均為「二元」運算符,操作的數據只能是整型(長短均可)或者char字符型。針對這些運算類型,下面分別給出示例,一目了然。

既然是運算,依舊可以分為簡單運算和複合運算兩大類進行歸類和講解。

小貼士:為了便於理解,字面量例子我就都使用二進位表示了,使用十進位(任何進位)不影響運算結果

簡單運算

簡單運算,顧名思義,一次只用一個運算符。

&:按位與

操作規則:「同為1則1,否則為0」。僅當兩個操作數都為1時,輸出結果才為1,否則為0。

說明:1、本示例(下同)中所有的字面值使用的都是十進位表示的,理解的時候請用二進位思維去理解;2、關於負數之間的位運算本文章統一不做講述

@Testpublic void test() {    int i = 0B100; // 十進位為4    int j = 0B101; // 十進位為5    // 二進位結果:100    // 十進位結果:4    System.out.println(&34; + Integer.toBinaryString(i & j));    System.out.println(&34; + (i & j));}

|:按位或

操作規則:「同為0則0,否則為1」。僅當兩個操作數都為0時,輸出的結果才為0。

@Testpublic void test() {    int i = 0B100; // 十進位為4    int j = 0B101; // 十進位為5    // 二進位結果:101    // 十進位結果:5    System.out.println(&34; + Integer.toBinaryString(i | j));    System.out.println(&34; + (i | j));}

~:按位非

操作規則:「0為1,1為0」。全部的0置為1,1置為0。

小貼士:請務必注意是全部的,別忽略了正數前面的那些0哦~

@Testpublic void test() {    int i = 0B100; // 十進位為4    // 二進位結果:11111111111111111111111111111011    // 十進位結果:-5    System.out.println(&34; + Integer.toBinaryString(~i));    System.out.println(&34; + (~i));}

^:按位異或

操作規則:「相同為0,不同為1」。操作數不同時(1遇上0,0遇上1)對應的輸出結果才為1,否則為0。

@Testpublic void test() {    int i = 0B100; // 十進位為4    int j = 0B101; // 十進位為5    // 二進位結果:1    // 十進位結果:1    System.out.println(&34; + Integer.toBinaryString(i ^ j));    System.out.println(&34; + (i ^ j));}

<<:按位左移

操作規則:把一個數的「全部位數」都向左移動若干位。

@Testpublic void test() {    int i = 0B100; // 十進位為4    // 二進位結果:100000    // 十進位結果:32 = 4 * (2的3次方)    System.out.println(&34; + Integer.toBinaryString(i << 2));    System.out.println(&34; + (i << 3));}

左移「用得非常多」,理解起來並不費勁。x左移N位,效果同十進位裡直接乘以2的N次方就行了,但是需要注意值「溢出」的情況,使用時稍加注意。

>>:按位右移

操作規則:把一個數的「全部位數」都向右移動若干位。

@Testpublic void test() {    int i = 0B100; // 十進位為4    // 二進位結果:10    // 十進位結果:2    System.out.println(&34; + Integer.toBinaryString(i >> 1));    System.out.println(&34; + (i >> 1));}

負數右移:

@Testpublic void test() {    int i = -0B100; // 十進位為-4    // 二進位結果:11111111111111111111111111111110    // 十進位結果:-2    System.out.println(&34; + Integer.toBinaryString(i >> 1));    System.out.println(&34; + (i >> 1));}

右移用得也比較多,也比較理解:操作其實就是把二進位數「右邊的N位」直接「砍掉」,然後正數右移高位補0,負數右移高位補1。

>>>:無符號右移

注意:沒有無符號左移,並沒有<<<這個符號的

它和>>有符號右移的區別是:無論是正數還是負數,「高位通通補0」。所以說對於正數而言,沒有區別;那麼看看對於負數的表現:

@Testpublic void test() {    int i = -0B100; // 十進位為-4    // 二進位結果:11111111111111111111111111111110(>>的結果) // 二進位結果:1111111111111111111111111111110(>>>的結果)    // 十進位結果:2147483646    System.out.println(&34; + Integer.toBinaryString(i >>> 1));    System.out.println(&34; + (i >>> 1));}

我特意把>>的結果放上面了,方便你對比。因為高位補的是0,所以就沒有顯示啦,但是你心裡應該清楚是怎麼回事。

複合運算

廣義上的複合運算指的是多個運算「嵌套起來」,通常這些運算都是同種類型的。這裡指的複合運算指的就是和=號一起來使用,類似於+= -=。本來這屬於基礎常識不用做單獨解釋,但誰讓A哥管生管養,管殺管埋呢。

混合運算:指同一個算式裡包含了bai多種運算符,如加減乘除乘方開du方等。

以&與運算為例,其它類同:

@Testpublic void test() {    int i = 0B110; // 十進位為6    i &= 0B11; // 效果同:i = i & 3 // 二進位結果:10 // 十進位結果:2    System.out.println(&34; + Integer.toBinaryString(i));    System.out.println(&34; + (i));}

複習一下&的運算規則是:「同為1則1,否則為0」

位運算使用場景示例

位運算除了「高效」的特點,還有一個特點在應用場景下不容忽視:「計算的可逆性」。通過這個特點我們可以用來達到「隱蔽數據」的效果,並且還保證了效率。

在JDK的源碼中。有很多初始值都是通過位運算計算的。最典型的如HashMap:

HashMap:  static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16 static final int MAXIMUM_CAPACITY = 1 << 30;

位運算有很多優良特性,能夠在「線性增長」的數據中起到作用。且對於一些運算,位運算是最直接、最簡便的方法。下面我安排一些具體示例(一般都是面試題),感受一把。

判斷兩個數字符號是否相同

同為正數or同為負數都表示相同,否則為不同。像這種小小case用十進位加上>/<比較符當然可以做,但用位運算符處理來得更加直接(效率最高):

@Testpublic void test4() {    int i = 100;    int j = -2;    System.out.println(((i >> 31) ^ (j >> 31)) == 0);    j = 10;    System.out.println(((i >> 31) ^ (j >> 31)) == 0);}

運行程序,輸出:

falsetrue

int類型共32bit,右移31位那麼就只剩下1個符號位了(因為是「帶符號右移動」,所以正數剩0負數剩1),再對兩個符號位做^異或操作結果為0就表明二者一致。

複習一下^異或操作規則:「相同為0,不同為1」

判斷一個數的奇偶性

在十進位數中可以通過和2取餘來做,對於位運算有一個更為「高效」的方式:

@Testpublic void test5() {    System.out.println(isEvenNum(1)); //false    System.out.println(isEvenNum(2)); //true    System.out.println(isEvenNum(3)); //false    System.out.println(isEvenNum(4)); //true    System.out.println(isEvenNum(5)); //false}/** * 是否為偶數 */private static boolean isEvenNum(int n) {    return (n & 1) == 0;}

為何&1能判斷奇偶性?因為在二進位下「偶數的末位肯定是0,奇數的最低位肯定是1」。而二進位第1位的前31位均為0,所以在和其它數字的前31位「與運算」後肯定所有位數都是0(無論是1&0還是0&0結果都是0),那麼唯一區別就是看最低位和1進行與運算的結果嘍:結果為1表示奇數,反則結果為0就表示偶數。

交換兩個數的值(不藉助第三方變量)

這是一個很古老的面試題了,交換A和B的值。本題如果沒有括號裡那幾個字,是一道大家都會的題目,可以這麼來解:

@Testpublic void test6() {    int a = 3, b = 5;    System.out.println(a + &34; + b);    a = a + b;    b = a - b;    a = a - b;    System.out.println(a + &34; + b);}

運行程序,輸出(成功交換):

3-------55-------3

使用這種方式最大的好處是:容易理解。最大的壞處是:「a+b,可能會超出int型的最大範圍,造成精度丟失導致錯誤,造成非常隱蔽的bug」。所以若你這樣運用在生產環境的話,是有比較大的安全隱患的。

小貼士:如果你們評估數字「絕無可能」超過最大值,這種做法尚可。當然如果你是字符串類型,請當我沒說

因為這種方式既引入了第三方變量,又存在重大安全隱患。所以本文介紹一種安全的替代方式,藉助位運算的「可逆性」來完成操作:

@Testpublic void test7() {    // 這裡使用最大值演示,以證明這樣方式是不會溢出的    int a = Integer.MAX_VALUE, b = Integer.MAX_VALUE - 10;    System.out.println(a + &34; + b);    a = a ^ b;    b = a ^ b;    a = a ^ b;    System.out.println(a + &34; + b);}

運行程序,輸出(成功完成交換):

2147483647-------21474836372147483637-------2147483647

由於全文都沒有對a/b做加法運算,因此不能出現溢出現象,所以是安全的。這種做法的核心原理依據是:「位運算的可逆性」,使用異或來達成目的。

位運算用在資料庫欄位上(重要)

這個使用case是「極具」實際應用意義的,因為在生產上我已用過多次,感覺不是一般的好。

業務系統中資料庫設計的尷尬現象:通常我們的數據表中可能會包含各種狀態屬性, 例如 blog表中,我們需要有欄位表示其是否公開,是否有設置密碼,是否被管理員封鎖,是否被置頂等等。「也會遇到在後期運維中,策劃要求增加新的功能而造成你需要增加新的欄位」,這樣會造成後期的維護困難,欄位過多,索引增大的情況, 這時使用位運算就可以「巧妙的」解決。

舉個例子:我們在網站上進行認證授權的時候,一般支持多種授權方式,比如:

  • 個人認證 0001 -> 1
  • 郵箱認證 0010 -> 2
  • 微信認證 0100 -> 4
  • 超管認證 1000 -> 8

這樣我們就可以使用1111這四位來表達各自位置的認證與否。要查詢通過微信認證的條件語句如下:

select * from xxx where status = status & 4;

要查詢既通過了個人認證,又通過了微信認證的:

select * from xxx where status = status & 5;

當然你也可能有排序需求,形如這樣:

select * from xxx order by status & 1 desc

這種case和每個人都熟悉的Linux權限控制一樣,它就是使用位運算來控制的:權限分為 r 讀, w 寫, x 執行,其中它們的權值分別為4,2,1,你可以隨意組合授權。比如 chomd 7,即7=4+2+1表明這個用戶具有「rwx」權限,

注意事項

  1. 需要你的DB存儲支持位運算,比如MySql是支持的
  2. 請確保你的欄位類型不是char字符類型,而應該是「數字類型」
  3. 這種方式它會導致「索引失效」,但是一般情況下狀態值是不需要索引的
  4. 具體業務具體分析,別一味地為了show而用,若用錯了容易遭對有噴的

流水號生成器(訂單號生成器)

生成訂單流水號,當然這其實這並不是一個很難的功能,最直接的方式就是日期+主機Id+隨機字符串來拼接一個流水號,甚至看到非常多的地方直接使用UUID,當然這是非常不推薦的。

UUID是字符串,太長,無序,不能承載有效的信息從而不能給定位問題提供有效幫助,因此一般屬於備選方案

今天學了位運算,有個我認為比較優雅方式來實現。什麼叫優雅:可以參考淘寶、京東的訂單號,「看似有規律,實則沒規律」

  • 不想把相關信息直接暴露出去。
  • 通過流水號可以快速得到相關業務信息,快速定位問題(這點非常重要,這是UUID不建議使用的最重要原因)。
  • 使用AtomicInteger可提高並發量,降低了衝突(這是不使用UUID另一重要原因,因為數字的效率比字符串高)

實現原理簡介

此流水號構成:日期+Long類型的值 組成的一個一長串數字,形如2020010419492195304210432。很顯然前面是日期數據,後面的一長串就蘊含了不少的含義:當前秒數、商家ID(也可以是你其餘的業務數據)、機器ID、一串隨機碼等等。

各部分介紹:

  1. 第一部分為當前時間的毫秒值。最大999,所以佔10位
  2. 第二部分為:serviceType表示業務類型。比如訂單號、操作流水號、消費流水號等等。最大值定為30,「足夠用了吧」。佔5位
  3. 第三部分為:shortParam,表示用戶自定義的短參數。可以放置比如訂單類型、操作類型等等類別參數。最大值定為30,肯定也是足夠用了的。佔5位
  4. 第四部分為:longParam,同上。用戶一般可放置id參數,如用戶id、商家id等等,最大支持9.9999億。絕大多數足夠用了,佔30位
  5. 第五部分:剩餘的位數交給隨機數,隨機生成一個數,佔滿剩餘位數。一般至少有15位剩餘(「此部分位數是浮動的」),所以能支持2的15次方的並發,也是足夠用了的
  6. 最後,在上面的long值前面加上日期時間(年月日時分秒)

這是A哥編寫的一個基於位運算實現的流水號生成工具,已用於生產環境。考慮到源碼較長(一個文件,共200行左右,無任何其它依賴)就不貼了,若有需要,

✍總結

位運算在「工程的角度」裡缺點還是蠻多的,在實際工作中,如果只是為了數字的計算,是不建議使用位運算符的,只有一些比較特殊的場景,使用位運算去做會給你柳暗花明的感覺,如:

  • N多狀態的控制,需要兼具擴展性。比如資料庫「是否狀態」的欄位設計
  • 對效率有極致要求。比如JDK
  • 場景非常適合。比如Jackson的Feature特徵值

切忌為了炫(zhuang)技(bi)而使用,炫技一時爽,掉坑火葬場;小夥還年輕,還望你謹慎。代碼在大多情況下,「人更容易讀懂比機器能讀懂來得更重要」

相關焦點

  • [洛穀日報第79期]二進位與位運算
    其他進位也可以用類似的方法進行轉換,例題P1143 進位轉換(https://www.luogu.org/problemnew/show/P1143)原碼、反碼和補碼原碼,指一個二進位數左邊加上符號位後所得到的碼,且當二進位數大於0時,符號位為0;二進位數小於0時,符號位為1;二進位數等於0時,符號位可以為0或1。
  • JAVA-二進位基礎
    ,即使其全部二進位位0,只要與一個各位都為零的數值相與,結果位零(2)取一個數中指定位,找一個數,對應X要取的位,該數的對應位為1,其餘為零,此數與X進行「與運算」可以得到X中的指定位2.2、按位或|只要有一個為1,結果就為10|0=0;1|0=1;0|1=1;1|1=1;用法:常用來對一個數據的某些位置設為1,找到一個數,對應X
  • python進階教程之進位、位運算
    進位、位運算1、什麼是進位1)理解個X進位的概念 :每一位 只允許出現 0~X-1 這幾個數字,逢X進一,基是X, 每一位有一個權值大小是X的冪次。 其表示的數值可以寫成按位權展開的多項式之十進位: 每一位只允許出現0~9這十個數字,逢十進1,基是十,每一位數字有一個 權值大小是十的冪次。
  • java基礎案例之java語言運算符算術賦值比較邏輯三元和位運算
    java運算符包含以下6種:1:算術運算符。 2:賦值運算符。 3:比較運算符。 4:邏輯運算符。 5:位運算符。 6:三元運算符。boolean類型,結果只有兩個1:true 2:false比較運算符裡頭有個==(等等於)他不同於=(等於)等於是賦值運算符,這點需要特別注意些才好,後面寫代碼時好多朋友在比較表達式裡頭,只寫了一個等號。
  • 跟我學java編程—不得不說的二進位和十六進位
    基數為r的r進位數可以表示為:● 二進位和十六進位數計算機就其本身來說是一個電器設備,為了能夠快速存儲、處理、傳遞信息,其內部採用了大量的電子元件,在這些電子元件中,電路的通和斷、電壓高低,這兩種狀態最容易實現,也最穩定、也最容易實現對電路本身的控制。計算機工程師將計算機所能表示這樣的狀態,用0,1來表示、即用二進位數表示計算機內部的所有運算和操作。
  • 你可能不知道,二進位比十進位更簡單
    在世界各文明獨立發展的數學中,出現過二十進位、六十進位、十六進位、十進位等,其中最廣泛採用的數制是十進位。亞里斯多德曾對此分析,可能是因為人有十個手指頭的緣故。直到現在,小朋友們學算術時還經常掰著手指頭算簡單的加減運算。
  • 十進位數的編碼與運算
    用得最普遍的是8421碼,即4個基2碼位的權從高向低分別為8、4、2和1,使用基2碼的0000、0001、…1001這10種組合,分別表示0到9這十個值。這種編碼的優點是這4位基2碼之間滿足二進位的規則,而十進位數位之間則是十進位規則,故稱這種編碼為以二進位編碼的十進位(Binary Coded Decimal)數,簡稱BCD碼或二-十進位碼。
  • MySQL涉及二進位的運算符:位運算符
    三者有一個共同點都是針對字符型、表達式和十進位的數字。那有沒有一種專門為二進位數字提供的運算符呢?這就是本問題的主題:位運算符。先看看位運算符的定義:位運算符用來對二進位字節中的位進行位移或者測試處理,MySQL中提供的位運算符有按位或(|)、按位與(&)、按位異或(^)、按位左移(<<)、按位右移(>>)、按位取反(~)等運算符。接下來就通過案例的方式來逐一解開這六類位運算符的什麼面紗。
  • 二進位小總結
    一個1或者0表示的數值位稱為一個bit,而計算機中存儲和傳輸數據的最小單位是一個字節(byte)也就是8個bit,所以說計算機所有計算本質上都是基於二進位。在計算機中,我們可以使用1個或者多個字節存儲一個數,但無論是多少個字節,其大小肯定是固定的,同時其所能表示的數值的範圍也是固定的。
  • 電腦,為什麼用二進位來運算?
    日常生活中,大家用的都是十進位,就是0-9組合出的各種數字;但電腦為什麼用二進位來存儲數據和運算?二進位是什麼,它和十進位有什麼關係?
  • 跟光磊學Java-變量和數據類型
    通過邏輯門可以組合使用實現更為複雜的邏輯運算和數值運算。邏輯門可以通過控制高、低電平,從而實現邏輯運算。電源電壓大小的波動對其沒有影響,溫度和工藝偏差對其工作的可靠性影響也比模擬電路小得多,所以相對穩定。因為數字計算機是由邏輯門組成,而邏輯電路最基礎的狀態就是兩個:開和關。所以,數字電路是以二進位邏輯代數為數學基礎。
  • 二進位中 1 的個數(劍指 Offer 題解Java版)
    二進位中 1 的個數題目連結NowCoder題目描述任意給定一個32位無符號整數n,求n的二進位表示中1的個數,比如n = 5(0101)時,返回2,n = 15(1111)時,返回4這也是一道比較經典的題目了
  • 跟光磊學Java-Java基本程序設計
    二進位的基本運算規則簡單,運算操作方便,這樣一來有利於簡化計算機內部結構,提高運算速度。但是在日常開發中,通常都會使用八進位和十六進位,因為八進位和十六進位相對於二進位表示數據更加簡潔,而且一個八進位表示三個二進位,一個十六進位表示四個二進位。例如1024使用二進位表示為0b100 0000 0000,使用八進位表示為02000,使用十六進位表示為0x400。
  • 程式設計師的情商:二進位電腦能識別,十進位人易懂,十六進位能做啥
    程式設計師的情商:二進位電腦能識別,十進位人易懂,十六進位能做啥?假如你有一個程式設計師的女朋友,突然給你發了一串數據(68656c6c6f 62616279),你知道什麼意思嗎?該怎麼回她呢?每天除了寫代碼,就是在學習寫代碼的路上。
  • 你應該知道的一些「位運算」……
    什麼是位運算我們知道程序中的所有數在計算機內存中都是以二進位的形式儲存的。位運算說白了,就是直接對整數在內存中的二進位位進行操作。因此,位運算最直接的好處就是節省內存空間,提高運算效率。它是把兩個操作數在二進位的形式上按位進行比較,如果都是1,則結果的這一位就為1;否則就為0。
  • C/C+編程筆記:C語言進位詳解,二進位、八進位和十六進位!
    進行加法運算時逢X進一(滿X進一),進行減法運算時借一當X,這就是X進位,這種進位也就包含X個數字,基數為X。十進位有 0~9 共10個數字,基數為10,在加減法運算中,逢十進一,借一當十。 二進位 我們不妨將思維拓展一下,既然可以用 0~9 共十個數字來表示數值,那麼也可以用0、1兩個數字來表示數值,這就是二進位(Binary)。例如,數字 0、1、10、111、100、1000001 都是有效的二進位。
  • java用二進位位標記權限
    簡單的使用二進位位來標記權限對應的二進位位為1擁有權限,0反之。
  • 加法器電路原理_二進位加法器原理_與非門二進位加法器
    二進位數11011相當於十進位數27。   二進位加法器是數字電路的基本部件之一。二進位加法運算同邏輯加法運算的含義是不同的。前者是數的運算,而後者表示邏輯關係。   圖2 全加器邏輯圖及其邏輯符號   例1、用4個全加器組成一個邏輯電路以實現兩個4位的二進位數A—1101(十進位為13)和B—1011(十進位為11)的加法運算。
  • 跟光磊學Java-Java運算符
    在Java底層(例如ArrayList源碼)大量使用了基於二進位的位運算。Java語言持7種位運算符左移(<<) :左移幾位就是乘以2的幾次方,二進位補碼左移n位,右邊補0右移(>>):右邊移幾位就是除以2的幾次方,二進位補碼右n位,左邊補0還是1取決於二進位補碼的最高位無符號右移(>>>):右邊移n位後,左邊補0,對於負數來說,右移後會變成正數
  • 6.4二進位的應用-現代計算機
    6.1語句與公式6.2符號的模擬——算術6.3符號的規則操作——計算6.4二進位的應用——現代計算機所有進位的位置記數法原理上等價,實踐中不同進位的記數法有不同的適用性。二進位是用0、1這兩個數字,以及逢二進一的規則來表示所有的數。