Python基礎(chǔ)之位運算符(含原碼反碼補碼的通俗解釋)

目錄

1 二進制
2 原碼萍肆、反碼削罩、補碼
3 位運算符
4 位運算符使用技巧


上回學(xué)習(xí)運算符時,漏了位運算符糊昙,因為位運算符理解起來稍微有點復(fù)雜辛掠,所以要單獨寫一篇~

要理解按位運算符,要先了解計算機進行存儲和計算的底層邏輯。

因此我們從最基礎(chǔ)的二進制說起萝衩。


1 二進制

只要學(xué)過計算機回挽,就不可能不知道二進制。

我們知道猩谊,十進制是逢十進一千劈,譬如11,左邊的1在十位上牌捷,代表10墙牌,右邊的1在個位上,就是1暗甥。

把1502這個數(shù)字拆開看喜滨,就是有1個1000,5個100撤防,0個10虽风,2個1, 1502=1*10^3+5*10^2+0*10^1+2*10^0寄月,也就是說辜膝,十進制中的位數(shù)對應(yīng)的就是10的冪,個位是0次冪漾肮,十位是1次冪厂抖,百位是2次冪,以此類推……

同理克懊,二進制中的位數(shù)對應(yīng)的就是2的冪验游,那么對于二進制下的1010,轉(zhuǎn)化成十進制下的數(shù)保檐,就是1*2^3+0*2^2+1*2^1+0*2^0=8+2=10

用2進制數(shù)數(shù)崔梗,首先是0夜只,然后是1,接下去是10蒜魄,而不是2扔亥,因為二進制中只有0和1。

小白可以練習(xí)一下從0寫到10谈为,寫完對一下結(jié)果:

image


2 原碼旅挤、反碼、補碼

這三個碼的產(chǎn)生伞鲫,都和表示減法(負數(shù))有關(guān)粘茄,他們的正數(shù)表示完全一樣

至于為什么為了表示個負數(shù),出現(xiàn)了三個碼柒瓣,我們一個一個來說儒搭。

2.1 原碼

日常生活中我們用負號(減號)解決了負數(shù)的表示問題,但在計算機中怎么加上這個負號呢芙贫?人們就想了個辦法搂鲫,用最高位存放符號,正數(shù)為0磺平, 負數(shù)為1魂仍。

以4位二進值數(shù)為例,最高位是符號位拣挪,那么后面只有三位來表示數(shù)字擦酌。例如,0001表示1媒吗,要表示-1仑氛,就把最高位寫成1礼搁,得到1001按摘。

當用8位來表示一個整數(shù)時,從右往左數(shù)的第8位即為符號位仪芒,當用16位來表示一個整數(shù)時甫何,從右往左數(shù)的第16位即為符號位出吹。我為了少寫點數(shù)字>.<,本文舉例都用4位辙喂。

原碼

這種方法簡單直觀捶牢,但在減法運算中有問題。計算1減去1巍耗,就是0001和1001加起來秋麸,會得到1010,這是咋了炬太?1加-1灸蟆,等于-2?

因此原碼無法進行減法運算亲族。


2.2 反碼

正數(shù)的反碼和正數(shù)的原碼完全一樣炒考,對負數(shù)原碼的非符號位取反,就得到負數(shù)的反碼(其實也就是將正數(shù)的反碼統(tǒng)統(tǒng)取反)霎迫,譬如+1的反碼是0001斋枢,-1的反碼就是1110。

反碼

此時我們計算+1和-1相加知给,即0001+1110=1111瓤帚,正好是-0,相反數(shù)相加等于0,沒有問題缘滥。

但此時一個0有了兩種表示法轰胁,0000和1111,一個數(shù)兩種表示朝扼,有點奇怪赃阀。

除此之外,雖然相反數(shù)相加沒有問題擎颖,但是其他數(shù)的減法依舊不對勁榛斯,譬如0010+1110,等于10000搂捧,最高位1溢出驮俗,就是0000,所以2-1=0允跑?王凑??

所以聋丝,這個碼還是不行索烹。


2.3 補碼

正數(shù)的補碼和正數(shù)的原碼完全一樣,負數(shù)的補碼等于負數(shù)的反碼+1弱睦。但是百姓,反碼加1并不是補碼的真正來歷,只不過補碼恰好等于反碼加1况木,這么計算更加方便而已垒拢。

補碼

關(guān)于補碼的本質(zhì)和定義,其實初看難以理解火惊,但是仔細想想求类,會發(fā)現(xiàn)這就是自然而然、渾然天成的東西屹耐。

我很喜歡一個詞尸疆,“十方圓滿”,一直以來我的微信簽名都是這四個字张症。那么,這個詞講的是怎樣一種狀態(tài)呢鸵贬?

  • 譬如俗他,我們原地轉(zhuǎn)個圈,就可以回到原點阔逼。
  • 譬如兆衅,我們在地球上,一直往東走可以到達的地方,一直往西走羡亩,也可以到達摩疑。
  • 譬如,我們把時鐘的時針往前撥180度畏铆,和往后撥180度雷袋,得到的結(jié)果是一樣的。
  • 再譬如辞居,愛因斯坦說楷怒,如果人能看到無限遠,那么他就能看到自己的后腦勺瓦灶。

我到底在說什么呢鸠删?

對于四位二進制數(shù),最大只能存放4位贼陶,就只有0000-1111這么大的空間刃泡,就只用2^4=16種排列組合的方式,空間是有限的碉怔。那么烘贴,這個空間圓不圓滿呢?我們想辦法讓它從線性變成圓就好了眨层,理解它庙楚,就像是理解24:00就是00:00,360°就是0°一樣趴樱。

先不管負數(shù)馒闷,假設(shè)我們有一條繩子,上面從左到右依次寫著0叁征、1纳账、2…15、16捺疼,就像這樣疏虫。


image

我們把繩子首尾相連,也就是把寫著0和16的兩端擰到一起啤呼,圈成一個圓卧秘。

image

這個圓上只有16個數(shù)字,16就等于0官扣,這是為了方便后面和四位二進制數(shù)的16種排列組合相對應(yīng)翅敌。

我們從0出發(fā),順時針走1個單位惕蹄,得到1蚯涮,逆時針走1個單位治专,得到15,1+15=16遭顶。同樣的张峰,順時針走7個單位得到7,逆時針走7個單位得到9棒旗,7+9=16喘批。這個16有個專業(yè)的叫法,叫做嗦哆。

這里的模是什么意思呢谤祖?簡單舉幾個例子:

  • 24小時制下,24就是模老速。
  • 轉(zhuǎn)一圈360°粥喜,360就是模。
  • 表上有12個刻度橘券,12就是模额湘。


    image

現(xiàn)在看這個圓,從0開始順時針轉(zhuǎn)旁舰,數(shù)值越來越大锋华,最后到15,再轉(zhuǎn)一個單位箭窜,就又回到0毯焕,沒有什么問題吧?

好磺樱,我們開始引入負數(shù)纳猫,并且把順時針看成加法,把逆時針看成減法竹捉,這下會得到什么呢芜辕?

順時針走1個單位,認為是加1块差,所以得到1侵续,圓的右邊還是1~7。逆時針走1個單位憨闰,就是減1状蜗,得到-1,同理鹉动,把圓的左邊都填滿轧坎,得到下圖。

image
  • 首先训裆,距離0相同距離的數(shù)眶根,相加等于0,這解決了相反數(shù)相加為0的問題边琉;
  • 其次属百,這個圓可以把減法轉(zhuǎn)化成加法,a-b=c变姨,其實等同于a+(16-b)=c族扰,因為模是16《ㄅ罚可以自己驗證下渔呵,譬如1-2=-1(逆時針走2個單位),在這里就等價與1+14=-1(順時針走14個單位)砍鸠。

完美袄┣狻!接下來爷辱,我們把這個圓上的十進制數(shù)字录豺,替換成二進制就好了。

image

問題來了饭弓,正數(shù)的二進制碼毫無疑問双饥,負數(shù)的二進制碼要怎么推出來呢?還有弟断,1對面那個問號應(yīng)該是什么數(shù)字咏花?在7和-7之間,應(yīng)該是8呢阀趴,還是-8呢昏翰?

先不管那個問號是什么數(shù),7的二進制碼是0111舍咖,再加1矩父,得到1000,問號處的二進制碼應(yīng)該是1000排霉,再加1窍株,就是10001,以此類推攻柠,我們就能補滿整個圓上的碼球订。

image

補完你會發(fā)現(xiàn),-1本就該是1111肮迮ァ冒滩!因為1111再加1,為10000浪谴,但因為四位开睡,最高位的1溢出了因苹,所以就得到0000,-1加1可不就是0嗎篇恒!

相應(yīng)的扶檐,我們可以驗證-4加4,即1100+0100胁艰,等于10000款筑,溢出位不算,0000疤诿础奈梳!這種表示法下,所有的相反數(shù)相加都是0000~

再看看別的減法呢解虱,譬如6-3攘须,即0110+1101,等于10011殴泰,即0011阻课,就是3~哈哈,都通過驗證了呢艰匙!

現(xiàn)在就剩最后一個問題了限煞,就是0的對面應(yīng)該是什么?從7出發(fā)员凝,加1應(yīng)該是8署驻,但是從-7出發(fā),減1應(yīng)該是-8健霹,這個1000到底代表哪個數(shù)旺上?

其實不難發(fā)現(xiàn),圓的右邊都是正數(shù)糖埋,最高位皆為0宣吱,左邊都是負數(shù),最高位皆為1瞳别,這有點像原碼中人為定義的最高位是符號位征候,所以1000自然而然應(yīng)該是-8。

雖然求補碼的過程中沒有特意留出一個符號位祟敛,但最終得到的補碼卻可以用最高位來判斷正負疤坝。補碼的符號位就是這么來的。

image

比比賴賴這么多馆铁,其實求補碼沒那么麻煩跑揉,可以匯總成一句話:正數(shù)補碼不變,求負數(shù)補碼用模減去其絕對值即可。

前面我們說過模是16历谍,那么求a-b现拒,其實等同于a+(16-b),所以求-b這個負數(shù)的補碼望侈,用16減b不就行了嗎具练?比如說,求-2甜无,就用16的二進制碼減去2的二進制碼「缯冢可是岂丘,四位二進制碼的空間里,根本沒有16這個數(shù)懊咭奥帘?沒有就對了,因為它是模仪召,也就是10000寨蹋,在八位中16的表示是00010000。

那么扔茅,我們計算-2的補碼已旧,其實就轉(zhuǎn)化成:
10000
-0010
=1110


2.4 小結(jié)

總結(jié)一下:

  • 原碼:將最高位作為符號位(0表示正,1表示負)召娜。
  • 反碼:如果是正數(shù)运褪,則和原碼一樣;如果是負數(shù)玖瘸,符號位為1秸讹,其余各位取反。
  • 補碼:如果是正數(shù)雅倒,則和原碼一樣璃诀;如果是負數(shù),將反碼加上1蔑匣。
image

很多文章在解釋補碼時劣欢,都是原碼→反碼→補碼這樣的思路。

先介紹最簡單的原碼裁良,它方便人讀數(shù)氧秘,但無法做減法,接著引申出反碼趴久,它是原碼過渡補碼的中間產(chǎn)物丸相,但無法解決0的問題,最后引出補碼彼棍,反碼直接加1即可得到補碼灭忠,這個碼可以完美解決前面兩個碼的問題膳算。但實際上我們也知道了補碼的發(fā)展過程并不如此,之所以提供這樣的思路弛作,只是為了便于計算補碼涕蜂。

關(guān)于補碼的定義和本質(zhì),我解釋得挺業(yè)余的映琳,舉的例子也不夠嚴謹机隙,主要是為了方便自己理解和記憶。要看專業(yè)的解釋萨西,就得去找權(quán)威書籍或教材來看了有鹿。


3 位運算符

計算機底層在存儲數(shù)據(jù)的時候,都是用補碼存儲谎脯,位運算符就是基于補碼進行的計算葱跋,包括:

  1. 位邏輯運算符: 與&,或|源梭,異或^娱俺,取反~。
  2. 位移運算符:左移<< 废麻,右移>> 荠卷。
位運算符 名稱 算法
& 按位與 兩個二進制數(shù)相應(yīng)位都為1,則該位的結(jié)果為1烛愧,否則為0
l 按位或 兩個二進制數(shù)相應(yīng)位有一個為1時僵朗,結(jié)果位就為1
^ 按位異或 兩個二進制數(shù)相應(yīng)位不同時,結(jié)果為1
~ 按位取反 對二進制進行取反屑彻,即 1 取反為 0 验庙,0 取反為 1
<< 按位左移 將二進制數(shù)左移n位,相當于乘以2的n次方
>> 按位右移 將二進制數(shù)右移n位社牲,相當于除以2的n次方粪薛,如果不能整除,則向下取整
a = 2
b = 3
print("a和b轉(zhuǎn)換為二進制為:", bin(a), bin(b))
-------------------------------------
[output]: a和b轉(zhuǎn)換為二進制為: 0b10 0b11

下面我就用2和3搏恤,也就是0010和0011舉例违寿。

a = 0010  #2
b = 0011  #3
 
a&b = 0010  #2
a|b = 0011  #3
a^b = 0001  #1
~a = 1101  #-3

a<<1 = 0100 #左移一位,相當于乘2熟空,得到4
a>>1 = 0001 #右移一位藤巢,相當于除以2,得到1
a>>2 = 0000 #右移兩位息罗,相當于除以4掂咒,不能整除時向下取整,得到0


4 位運算符使用技巧

在日常工作中,用到位運算符的場景似乎不多绍刮,它能用來做什么呢温圆?

4.1 按位與

通常,我們寫程序判斷奇偶數(shù)孩革,是除以2看余數(shù)∷昵福現(xiàn)在可以用該數(shù)和1進行按位與,結(jié)果是1膝蜈,就是奇數(shù)锅移,是0,則為偶數(shù)饱搏。

def Odd_Even(x):
    if x&1 == 1:
        print(x,'是奇數(shù)')
    else:
        print(x,'是偶數(shù)')

Odd_Even(666)
---------------------
[output]: '666 是偶數(shù)'

4.2 按位或

任意數(shù)和1按位或非剃,可以向上求最接近的奇數(shù)。

6|1
---------------------
[output]: 7

7|1
---------------------
[output]: 7

4.3 按位異或

一個數(shù)a窍帝,另一個數(shù)b進行兩次異或運算,最后結(jié)果不變诽偷,即(a ^ b) ^ b = a坤学。

5^7
---------------------
[output]: 2

5^7^7
---------------------
[output]: 5

因此用異或運算調(diào)換兩個數(shù)字的值。

a = 5
b = 7
a = a^b
b = b^a
a = a^b
print(a,b)
---------------------
[output]: 7 5

當然Python中其實可以用一行代碼就完成交換报慕。

a = 5
b = 7
a,b = b,a
print(a,b)
---------------------
[output]: 7 5

簡單的加密也可以用異或運算深浮,比如實際密碼是password,既怕忘了又怕直接寫下來被別人看到眠冈,就可以用一個簡單的key作為密鑰飞苇,兩者作異或運算,得到tip蜗顽,把這個tip記到小本子里布卡。忘記密碼時,將key和tip做異或運算雇盖,就能得到原密碼啦~

password = 587645
key = 111111
tip = password ^ key
print(tip)
---------------------
[output]: 607610

tip ^ key
---------------------
[output]: 587645

4.4 按位取反

對一個數(shù)按位取反忿等,等于它的相反數(shù)減1。

~55
---------------------
[output]: -56

對一個數(shù)兩次取反崔挖,結(jié)果不變贸街。

~~55
---------------------
[output]: 55

4.5 按位左移

a左移b位,就是把a轉(zhuǎn)為二進制后左移b位狸相,后面缺位補0薛匪,相當于a乘以2的b次方,因為在二進制數(shù)后添一個0就相當于該數(shù)乘以2脓鹃。

5<<2
---------------------
[output]: 20

4.6 按位右移

a右移b位逸尖,就是把a轉(zhuǎn)為二進制后右移b位,前面缺位補0,相當于a除以2的b次方冷溶,并向下取整渐白。

14>>2
---------------------
[output]: 3

計算機中的數(shù)是用二進制來表示的,因此位運算可以更直接逞频、更高效地實現(xiàn)運算操作纯衍。對于乘2除2,二進制左右位移一下就搞定苗胀,速度非辰笾睿快,所以盡量用位移來代替代碼中的乘除基协。

最后注意一點歌亲,在Python中只能對整數(shù)進行位運算~


文中圖片的水印網(wǎng)址為本人CSDN博客地址:BeSimple

參考鏈接:
1)原碼、反碼澜驮、補碼的產(chǎn)生陷揪、應(yīng)用以及優(yōu)缺點有哪些? - 張?zhí)煨械幕卮?- 知乎
2)原碼杂穷,反碼悍缠,補碼的深入理解與原理
3)Python位運算用途以及用法
4)js 中位運算的應(yīng)用
5)位運算簡介及實用技巧(一):基礎(chǔ)篇

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市耐量,隨后出現(xiàn)的幾起案子飞蚓,更是在濱河造成了極大的恐慌,老刑警劉巖廊蜒,帶你破解...
    沈念sama閱讀 216,402評論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件趴拧,死亡現(xiàn)場離奇詭異,居然都是意外死亡山叮,警方通過查閱死者的電腦和手機著榴,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來屁倔,“玉大人兄渺,你說我怎么就攤上這事√郑” “怎么了挂谍?”我有些...
    開封第一講書人閱讀 162,483評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長瞎饲。 經(jīng)常有香客問我口叙,道長,這世上最難降的妖魔是什么嗅战? 我笑而不...
    開封第一講書人閱讀 58,165評論 1 292
  • 正文 為了忘掉前任妄田,我火速辦了婚禮俺亮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘疟呐。我一直安慰自己脚曾,他們只是感情好,可當我...
    茶點故事閱讀 67,176評論 6 388
  • 文/花漫 我一把揭開白布启具。 她就那樣靜靜地躺著本讥,像睡著了一般。 火紅的嫁衣襯著肌膚如雪鲁冯。 梳的紋絲不亂的頭發(fā)上拷沸,一...
    開封第一講書人閱讀 51,146評論 1 297
  • 那天,我揣著相機與錄音薯演,去河邊找鬼撞芍。 笑死,一個胖子當著我的面吹牛跨扮,可吹牛的內(nèi)容都是我干的序无。 我是一名探鬼主播,決...
    沈念sama閱讀 40,032評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼衡创,長吁一口氣:“原來是場噩夢啊……” “哼帝嗡!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起钧汹,我...
    開封第一講書人閱讀 38,896評論 0 274
  • 序言:老撾萬榮一對情侶失蹤丈探,失蹤者是張志新(化名)和其女友劉穎录择,沒想到半個月后拔莱,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,311評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡隘竭,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,536評論 2 332
  • 正文 我和宋清朗相戀三年塘秦,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片动看。...
    茶點故事閱讀 39,696評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡尊剔,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出菱皆,到底是詐尸還是另有隱情须误,我是刑警寧澤,帶...
    沈念sama閱讀 35,413評論 5 343
  • 正文 年R本政府宣布仇轻,位于F島的核電站京痢,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏篷店。R本人自食惡果不足惜祭椰,卻給世界環(huán)境...
    茶點故事閱讀 41,008評論 3 325
  • 文/蒙蒙 一臭家、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧方淤,春花似錦钉赁、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至邑蒋,卻和暖如春姓蜂,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背医吊。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評論 1 269
  • 我被黑心中介騙來泰國打工钱慢, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人卿堂。 一個月前我還...
    沈念sama閱讀 47,698評論 2 368
  • 正文 我出身青樓束莫,卻偏偏與公主長得像,于是被迫代替她去往敵國和親草描。 傳聞我的和親對象是個殘疾皇子览绿,可洞房花燭夜當晚...
    茶點故事閱讀 44,592評論 2 353

推薦閱讀更多精彩內(nèi)容