有趣的二進制

優秀應用算法都大量用到位運算,而位運算在工作中很少用到,大多數教材只會教大家二進制和十進制如何互換,都是死記硬背式的,并沒有去講解真正含義,換一個進制之后,依然不會,我們回到最根本的一些計數方法上,從10進制來推算,希望用一種更簡單的方式介紹其原理。


我們來看上一篇的一個Varint算法,這個算法的目的是為了令一個整型占用更少的字節,比如小于127的數字,只需占用一個字節即可,小于16384的數字,采用2個字節即可。算法如下:

我們來看看具體圖例:

我們看到在小于2097153期間,占用空間會小于4個字節,這個優勢還比較明顯,不過也有弊端,比如超過268435456之后會有占用5個字節,考慮到大多數情況下,并不會應用到這么大的數字,優化空間方面還是不錯的。

通過上述算法實現,我發現優秀的應用算法都會大量用到了位運算,而位運算在工作中卻很少用到。位運算速度要快于整數運算的,特別是整數乘法,需要10個或者更多個時鐘,若果采用移位操作一個或者2個時鐘就夠了,不過由于我們常采用十進制來進行算術運算,對二進制的位運算不夠熟悉,閱讀起來會比較耗費精力,所以借助上述算法實現,我們分析一下位運算的優勢以及應用,從而更好的理解二進制。上述代碼中,有運用到移位操作,位運算,字節序等相關知識點,我們一一分析。

進位制

我們知道,計算機的存儲和處理的信息都是以二進制的,雖然在編寫程序的期間數運算還是采用10進制表示,但到機器執行的時候,還會以2進制來進行處理。對于有10個指頭的人來說,熟知10進制是很自然的事情,你看教小孩子數學的時候,都是先從數指頭開始的,那么若是我們只有2個指頭,是不是我們現在會更好理解二進制了?

其他進制轉換10進制

大多數教材會教大家二進制和十進制如何互換,但多數說都是死記硬背式的,并沒有去講解真正含義,換一個進制之后,依然不會,我們回到最根本的一些計數方法上,從10進制來推算。比如我們看一個數字1001,采用十進制表示是:1x10^3+0*10^2+0*10^1+1*10^0。首先從右往左,我們可以看成是從低位到高位,每高一位,指數+1,其次10進制是以10為底數,其三這個公式是采用10進制算術進行計算的(用什么進制算出答案就相當于把當前進制轉換為了什么進制了)。這個方式適合所有的進制轉換,理解了這個,后續的進制轉換都會很容易理解。

2進制的比較簡單,我們直接忽略,我們來看下應用到3進制,同樣是1001,轉換10進制公式:1x3^3+0*3^2+0*3^1+1*3^0=28,我們發現只是底數改變,因為是3進制,所以以3為底數,另外計算方式還是采用10進制算式計算,這表明用10進制算出的答案,就相當于3進制轉換為10進制,1001轉換為10進制就是28。

那為何不采用其他進制來計算?采用其他進制計算,那么其他進制的乘法口訣你的熟練一遍了,比如10進制的99乘法口訣,你用其他進制的乘法口訣得自己來演繹一遍了,如此這個和我們的常用習慣有些相駁,換算起來會比較慢,所以一般采用十進制與其它進制互轉或者作為中間步驟來處理。

10進制轉換為其他進制

采用上述方法后,我們已經可以做到所有進制轉換,包括10進制轉3進制,比如十進制28轉換為3進制28=2*3+22,這個采用3進制(3的三進制表示10)來進行計算,但是會很麻煩。所以10進制轉換其他進制,我們常采用短除法,如下:

當前數不斷除以3并把余數作為新的最高位,28除以3余1,1為“個位”,9除以3余0,0為“十位”,3除以3余0,0為“百位”,最終的1是“千位”。如果我們有注意到前面的3進制轉10進制算法,我們可以發現短除法其實是3進制轉10進制的逆操作,比如3進制轉換為十進制時候是:1*3^3+0*3^2+0*3^1+1*3^0? ,我們轉換一下是((1*3+0)*3+0)*3+1,如此和10進制轉換3進制的時候逆向操作。

小數

如果前面的理解了,小數就可以很容易理解了,我們還是先從10進制來看。比如十進制12.34,我們看小數后面十分位部分.3,表示把1分為10份只取3份,.04百分位部分是把1分為100份,取4份。那么我們換成公式:

我們看到小數部分還是以進制為底數,不過指數部分采用了負數,點的左邊的位的指數是位的正冪,點數的右邊是位的指數負冪。理解了這個,其他進制的小數部分也就了解, 它們是相同的,比如二進制1001.101:


有了這個理解,我們后續的浮點數就比較好理解了,IEEE浮點表示浮點數,也是基于這種方式,只是定義了些規范,后續我們會詳細了解。

移位操作

常見的移位操作有三種:左移,邏輯右移,算術右移。

移動操作


左移

x向左移動k位,會丟棄最高的k位,并在右端補k個0,也就是常說的當前值乘以2的k次方。為何是乘以2的k次方?我們看10進制的時候,某數乘以10,就是在末尾增加1個0 ,由此我們可以聯想到,二進制左移一位(末尾加一個0)相當于乘以2,這個結論普遍存在于所有進位制中:k進制數的末尾加個0,相當于該數乘以k。


我們從圖中可以看到,左移動一位,就相當于進位制展開式的每個指數都加1,如此移動一位,就相當于當前數(1*2^5+1*2^1+!*2^0)*2^1=1*2^6+1*2^2+1*2^1

右移

理解了左移的原理,右移動的原理也是相同的,右移k位=進位制展開式的每個指數都減k,也就是當前數除以進制的k次方。唯一不同的是分為邏輯右移和算術右移。

邏輯右移就是無符號移位,右移幾位,就在左端補幾個0,比如上邊?Varint中每次右移7位,相應的當前數高位就會補充7個0。

算術右移動是有符號移位,和邏輯右移不同的是,算術右移是在左端補k個最高有效位的值,如此看著有些奇特,但對有符號整數數據的運算非常有用。我們知道有符號的數,首位字節,是用來表示數字的正負。負數采用補碼形式來存儲,比如[11100110],10進制是-26,算術右移1位之后[11110011],10進制是-13,如若不是補最高有效位的值1而是補做事0的話,右移之后就變成正數了。

字節序

單個字節并沒有字節序的問題,當一個數據需要多個字節存儲的時候,就會牽扯到這樣的問題,這個數據的地址是什么,存儲器中如何排列這些字節,是高位地址存最高有效位,還是低位地址存最高有效位。

比如一個int類型的變量,它的地址是使用字節中最小的地址,比如在存儲器上的位置是0x101、0x102、0x103,它的地址是0x101,若是這個數據是一個w位的整數,位表示為[x(w-1),x(w-2)....,x1,x0],那么其中x(w-1)是最高有效位,x0是最低有效位,w若是8的倍數,位被分組成字節,那么最高有效字節是[x(w-1)...x(w-8)],最低有效字節是[x7,x6...x0]。這個也可以成為物理順序,和我們普通人理解的存儲順序預期相符合,比如十進制也是高位(百位,10位)在地位(個位)前面。

小端法(little endian)

如果字節的邏輯順序與物理順序相反,也就是w的最低有效字節在前面[x7,x6....x0],最高有效字節[x(w-1)...x(w-8)]在后面,此時成為小端法(little endian)。多數intel兼容機都采用這種規則。

大端法(big endian)

如果字節的邏輯順序與物理順序相同,也就是w的最低有效字節[x(w-1)...x(w-8)]在前面,最高有效字節[x7,x6....x0]在后面,稱為大端法(big endian),大多數IBM和Su你Microsystems的機器都是采用這種規則。

比如一個十六進制數:0x01234567,我們用大端小端法看他們在存儲器上的位置。


我們可以看到大端法是比較符合我們習慣的,高位在前地位在后。

上述Varint的算法,是采用小端法來存儲字節順序的。

每次都是獲取當前數據的后7個字節存儲到數據流buffer里面,也就是低位字節放在buffer字節數組的前面。

----------------------------------------------end------------------------------------------------

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,237評論 6 537
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,957評論 3 423
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,248評論 0 382
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,356評論 1 316
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,081評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,485評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,534評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,720評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,263評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,025評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,204評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,787評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,461評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,874評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,105評論 1 289
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,945評論 3 395
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,205評論 2 375

推薦閱讀更多精彩內容

  • 國家電網公司企業標準(Q/GDW)- 面向對象的用電信息數據交換協議 - 報批稿:20170802 前言: 排版 ...
    庭說閱讀 11,062評論 6 13
  • 8086匯編 本筆記是筆者觀看小甲魚老師(魚C論壇)《零基礎入門學習匯編語言》系列視頻的筆記,在此感謝他和像他一樣...
    Gibbs基閱讀 37,311評論 8 114
  • 簡介 用簡單的話來定義tcpdump,就是:dump the traffic on a network,根據使用者...
    保川閱讀 5,978評論 1 13
  • 川流不息霓虹燈閃爍,窗外的夜依舊繁華如晝。 我關了燈,蜷縮在無盡黑暗。 我沒有拉上窗簾。窗子很大,窗外的顏色好多好...
    萬妍閱讀 249評論 1 1
  • 巴哥閱讀 186評論 0 1