之前學(xué)習(xí)的原碼忌怎、反碼、補(bǔ)碼之間的轉(zhuǎn)換酪夷,都是課本上教的榴啸,但是不知道為啥要那么轉(zhuǎn)換,最近在看《編碼》這本書(shū)晚岭,講到加法器的實(shí)現(xiàn)鸥印,又看到了補(bǔ)碼,就決定把這幾個(gè)的關(guān)系研究研究
以下故事純屬虛構(gòu)坦报,為了直觀(guān)簡(jiǎn)單所有運(yùn)算都是按照4bit運(yùn)算來(lái)講解库说,4bit最多表示16個(gè)數(shù),0~15 或者-8~7 所以別越界哦片择,下面開(kāi)始講故事 ~
很早以前有個(gè)路人甲發(fā)明了二進(jìn)制潜的,逢二進(jìn)一,3就用(0011=0*23 + 0*22 + 1*21 + 1*2o)表示字管,2就用(0010=0*23 + 0*22 + 1*21 + 0*2o)來(lái)表示夏块,那么負(fù)3和負(fù)2用啥來(lái)表示呢疏咐,突然想到手寫(xiě)的10進(jìn)制中纤掸,負(fù)數(shù)是在前面加一條橫杠比如-6脐供、-2,所以想二進(jìn)制也用加一條"橫杠"來(lái)表示負(fù)數(shù)吧,所以在最左邊是1(橫杠)的就是負(fù)數(shù),不是1的就是正數(shù)借跪。
后來(lái)發(fā)明了計(jì)算機(jī)政己,由于計(jì)算機(jī)實(shí)現(xiàn)加法運(yùn)算還算容易,實(shí)現(xiàn)減法非常復(fù)雜(會(huì)在另一篇文章講解加法器)掏愁,所以就只有加法器歇由,那么減法運(yùn)算只能轉(zhuǎn)化成加法,減一個(gè)數(shù)等于加一個(gè)數(shù)的負(fù)數(shù)果港,然后計(jì)算機(jī)就用路人甲發(fā)明的表示負(fù)數(shù)的方法進(jìn)行運(yùn)算
(1) 2+3 = 0010 + 0011 = 0101 = 5 ? ? ?倆正數(shù)相加還是不錯(cuò)的 ~
(2) 3-2 = 3 + (-2) = 0011 + 1010 = 1101 = -5 ? ?what沦泌?咋是-5 ,仔細(xì)看發(fā)現(xiàn),只要是一個(gè)正數(shù)一個(gè)負(fù)數(shù)相加辛掠,最左邊肯定是1谢谦,那就肯定是負(fù)數(shù)了 ,不合理
(3) 2-3 = 2 + (-3) = 0010 + 1011 = 1101 = -5 ?what? 同上 ~
(4) -2 -3 = -2 + (-3) = 1010 +1011 = 0101 = 10101 因?yàn)榉?hào)位相加導(dǎo)致溢出萝衩,最高位溢出結(jié)果為0101 = 5?
(5) 0 + 0 = 0000 + 0000 = 0, ? 0 - 0 = 0 ?+ (-0) = 0000 + 1000 = 1000 = -0回挽, -0 - 0 = -0 + (-0) = 1000 + 1000 = 0000 = +0 ? ?運(yùn)算沒(méi)錯(cuò),只是有正負(fù)0而已
從上面可以看出猩谊,符號(hào)位參與運(yùn)算是有很大問(wèn)題的千劈,導(dǎo)致運(yùn)算結(jié)果不對(duì),那么怎么才能不讓符號(hào)位進(jìn)行運(yùn)算呢 ~ 很簡(jiǎn)單牌捷,路人乙想到了一個(gè)號(hào)方法
反碼要產(chǎn)生了
路人乙想 :符號(hào)位的產(chǎn)生墙牌,就是為了表示負(fù)數(shù)的,如果我表示負(fù)數(shù)的時(shí)候不用符號(hào)位暗甥,用另一種方式喜滨,是不是可以呢,結(jié)果就想到了用相反數(shù)表示負(fù)數(shù)淋袖,比如3 = 0011鸿市,因?yàn)槎M(jìn)制非0即1,所以-3可以將3(0011)按位取反得到1100,用1100表示-3,啊呀即碗,這樣不就沒(méi)有符號(hào)位了焰情。“反碼”就產(chǎn)生了剥懒,用相反數(shù)表示負(fù)數(shù)的編碼方式叫反碼内舟,那路人甲原來(lái)發(fā)明的編碼方式就叫負(fù)數(shù)的"值"等于正數(shù)的"值"所以叫原碼,(但是這種表示方式在讀取負(fù)數(shù)的值的時(shí)候是不方便的初橘,比如給你個(gè)1100验游,你必須得轉(zhuǎn)換成他對(duì)應(yīng)的正數(shù)0011(3)充岛,才知道是0011的反碼,是"負(fù)0011"(-3))
那原碼和反碼啥關(guān)系呢 原碼表示3用0011 反碼表示3也用0011 耕蝉,所以正數(shù)的原碼等于反碼崔梗,原碼表示-3用1011,反碼表示-3是1100 ?所以負(fù)數(shù)的反碼等于原碼非符號(hào)位取反
這是百度百科對(duì)反碼的解釋?zhuān)灰逊创a和相反數(shù)弄混了垒在,反碼專(zhuān)門(mén)就是給咱們程序員造的詞 ~
接下來(lái)咱們看看沒(méi)有符號(hào)位的反碼進(jìn)行運(yùn)算蒜魄,結(jié)果會(huì)怎么樣呢, 注意結(jié)果也是反碼,下面已經(jīng)沒(méi)有符號(hào)位這一說(shuō)了
(1) 2+3 = 0010 + 0011 = 0101 = 5 ? ? ?正數(shù)和原碼一樣,所以結(jié)果也是對(duì)的
(2) 3-2 = ?0011 - 0010 =?3 + (-2) =? 0011 +1101 = 10000 最高位溢出結(jié)果為0000 = 0,應(yīng)該是1結(jié)果是0?
(3) 2-3 = 0010 - 0011 = 2 + (-3) = 0010 + 1100 = 1110(反碼,是一個(gè)負(fù)數(shù)) = -0001(轉(zhuǎn)成正數(shù)) = -1 可以
(4) -2 -3 = ?-2 + (-3) = 1101 +1100 ?= 11001 最高位溢出后是1001 = -6 應(yīng)該是-6結(jié)果少了1變成-6了
(5) 0 + 0 = 0000 + 0000 = 0000 = +0
? ? ? 0 - 0 = 0 ?+ (-0) = 0000 + 1111 = 1111 = -0场躯,
?????-0 - 0 = -0 + (-0) = 1111 + 1111 = 1 1110 = 1110 這個(gè)不對(duì)了谈为,不管是+0還是-0都不是
仔細(xì)觀(guān)察可以發(fā)現(xiàn)以下規(guī)律
(1) 正數(shù) + 正數(shù) = 正數(shù) ----沒(méi)問(wèn)題
(2) 正數(shù) + 負(fù)數(shù) = 正數(shù)------結(jié)果少1
(3) 負(fù)數(shù) + 正數(shù) = 負(fù)數(shù)-----沒(méi)問(wèn)題
(4) 負(fù)數(shù) + 負(fù)數(shù) = 負(fù)數(shù)------結(jié)果少1
(5) -0 + -0 是不對(duì)的 -----結(jié)果多1
補(bǔ)碼要產(chǎn)生了
眼看路人乙的想法也行不通,路人丙看到上面的規(guī)律(1)發(fā)現(xiàn)全是正數(shù)加是沒(méi)問(wèn)題的踢关,從(2)可以看出伞鲫,如果負(fù)數(shù)的表現(xiàn)形式在之前反碼的表現(xiàn)形式上再補(bǔ)個(gè)1,那么(2)就沒(méi)問(wèn)題了签舞,結(jié)果發(fā)現(xiàn)(4)也變得沒(méi)問(wèn)題了秕脓。因?yàn)槭鞘茄a(bǔ)了個(gè)1得來(lái)的,那就叫補(bǔ)碼吧 ~ 下面咱們來(lái)運(yùn)算一下看看
公式由之前的 (負(fù)數(shù) = 正數(shù)各位取反) ?----> ?(負(fù)數(shù) = 正數(shù)各位取反 + 1)
(1) 2+3 = 0010 + 0011 = 0101 = 5 ? ? ?正數(shù) + 正數(shù)是和反碼沒(méi)區(qū)別的瘪菌,所以沒(méi)問(wèn)題
(2) 3-2 = ?0011 - 0010 =?3 + (-2) =? 0011 +(1101 + 1) =?0011 +1110?= 10001 最高位溢出結(jié)果為0001 = 1
(3) 2-3 = 0010 - 0011 = 2 + (-3) = 0010 + (1100 +1) ?= ?0010 + 1101?= 1111 ?補(bǔ)碼運(yùn)算撒会,得到的也是補(bǔ)碼,那這個(gè)補(bǔ)碼是個(gè)負(fù)數(shù)师妙,對(duì)應(yīng)的值是多少呢诵肛,根據(jù)公式 (負(fù)數(shù) = 正數(shù)各位取反 + 1)?則1111-1 = 1110 再取反 是0001 ?= 1,所以1111是正1的補(bǔ)數(shù)默穴,那就是負(fù)一
(4)-2 -3 = ?-2 + (-3) =(1101 + 1) + (1100 + 1) = 11011 = 最高位溢出后是1011 對(duì)應(yīng)的正數(shù)是 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?5((0101))怔檩,所以是5的補(bǔ)碼,那就是負(fù)5
哇蓄诽,運(yùn)算的問(wèn)題終于解決了薛训,但是補(bǔ)碼只是用來(lái)運(yùn)算的,他的負(fù)數(shù)表示太不直觀(guān)仑氛,所以最終定的是乙埃,二進(jìn)制的正負(fù)數(shù)還是用原碼表示(直觀(guān),咱們開(kāi)發(fā)者變成的時(shí)候還是用原碼便是),但是運(yùn)算的時(shí)候用補(bǔ)碼運(yùn)算(數(shù)值在計(jì)算中就是用補(bǔ)碼存的锯岖,運(yùn)算也是用補(bǔ)碼)
補(bǔ)充
上面補(bǔ)碼的產(chǎn)生說(shuō)的是根據(jù)反碼介袜,找出來(lái)的規(guī)律 ~這是我自己編的。出吹。遇伞。绪囱。侍郭。欣范,但是補(bǔ)碼運(yùn)算確實(shí)是沒(méi)問(wèn)題的
下面說(shuō)說(shuō)正經(jīng)的锌介,為啥叫補(bǔ)碼呢,可能就是有點(diǎn)互補(bǔ)的意思的渐排,A+B = 固定的數(shù)炬太。A和B是互補(bǔ)的。從搜索的資料來(lái)看飞盆,大部分說(shuō)的是根據(jù)“穆α穑”時(shí)鐘啟發(fā)來(lái)的。比如時(shí)鐘一共12個(gè)數(shù)吓歇,1到12點(diǎn),那么2+10 = 12票腰、4+8=12城看,那2和10,4和8都是互補(bǔ)的杏慰。比如現(xiàn)在指針指向12點(diǎn)测柠,想讓時(shí)鐘指到 1點(diǎn),可以順時(shí)針+1 也可以逆時(shí)針 減11 ,也就是 -(12-1)缘滥。想讓時(shí)鐘指向10點(diǎn)轰胁,可以逆時(shí)針 -2 也可以順勢(shì)針 +10。結(jié)論就是
順勢(shì)針撥的數(shù)(也就是絕對(duì)值) + 逆時(shí)針撥的數(shù)(也就是絕對(duì)值) = 總的個(gè)數(shù)朝扼,兩個(gè)數(shù)還是對(duì)于12說(shuō)是互補(bǔ)
聽(tīng)起來(lái)有那么點(diǎn)道理赃阀,但是現(xiàn)在是中午十二點(diǎn),我順勢(shì)針+1是下午1點(diǎn)擎颖,逆時(shí)針-11是凌晨1點(diǎn)榛斯,位置是一樣,可他媽時(shí)間不一樣啊 ~ 帶著疑問(wèn)運(yùn)算一把看看搂捧,咱們就只運(yùn)算那兩個(gè)之前有問(wèn)題的(2)和(3)驮俗,首先咱們舉例都是4bit進(jìn)行運(yùn)算的也就是 內(nèi)存占用是這樣的?
口口口口?
四個(gè)格子,能表示的數(shù)是2的4次方 = 16也就是0-15允跑,再注意一點(diǎn)就是用這種方式代替負(fù)數(shù)就是不想有符號(hào)位王凑,所以下面的運(yùn)算中所有的數(shù)最高位不代表符號(hào),是數(shù)值位
(2) 3-2 = 3 + (16 -2) = 3 + 14 = 0011 + 1110 = 10001 去掉溢出的最高位是0001 = 1
(4)-2 -3 = (16 - 2) + (16 - 3) = 14 + 13 = 1110 + 1101 = 11011 = 最高位溢出 1011 是11
啊呀聋丝,一看用"模"運(yùn)算也不對(duì)啊 ~到底咋回事 ~ 突然想到我的疑問(wèn)索烹,下午一點(diǎn)和凌晨一點(diǎn)能一樣嗎? 答案是 不一樣 潮针!
接下來(lái)繼續(xù)講解怎么就對(duì)了
把上面的(2)(4)再說(shuō)一下
(2) 3-2 = 3 + (16 -2) = 3 + 14 = 0011 + 1110 = 10001 去掉溢出的最高位是0001 = 1术荤,咱們本來(lái)是-2結(jié)果變成了+14,雖然位置一樣每篷,但是多轉(zhuǎn)了一圈啊瓣戚。咱們?cè)倏从疫?10001端圈,溢出以后咱們把最高位丟棄了,只剩0001子库,那么丟棄的最高位代表的就是16舱权,就是一圈啊,等號(hào)左邊多加了一圈仑嗅,右邊減了一圈宴倍,所以沒(méi)毛病 ~按照上面的公式??3-2 = 0011 + 1110 = 10001,那-2可以用1110代替,那-2就是2(0010)取反加一
(4)-2 -3 = (16 - 2) + (16 - 3) = 14 + 13 = 1110 + 1101 = 11011 = 最高位溢出 1011 是11(在這沒(méi)符號(hào)位這一說(shuō))
那這個(gè)怎么解釋呢仓技?
左邊多了兩圈鸵贬,右邊溢出一個(gè),少了一圈脖捻,那右邊還有多的一圈,說(shuō)明1011還是多了一圈的阔逼,所以雖然結(jié)果是1011(11),但是他是多了16的地沮,所以實(shí)際應(yīng)該是-5嗜浮,1011代表的-5也就是正5取反 + 1
(5)?-0 - 0 = -0 + (-0) =?(16 -0)?+?(16 -0)?=?(1111 + 0001)??+?(1111 + 0001)?= ?1111 + 1111 + 0001 + 0001 = ?1110 + 0010 = ??1 0000 去掉最高位后是0000 是0,但是根據(jù)上面說(shuō)的摩疑,0000應(yīng)該還得減去一圈那就是0000代表的是-16
僅僅是表示而已危融,比如一個(gè)字節(jié)是8位,如果有符號(hào)的話(huà)表示-128 ~ 127 但是你用過(guò)-128 嗎
總結(jié)一下:
(1)原碼雷袋、反碼吉殃、補(bǔ)碼,是互相獨(dú)立的片排,不存在依賴(lài)關(guān)系寨腔,只是之間的表示方法存在規(guī)律
(2)原碼、反碼率寡、補(bǔ)碼都是針對(duì)負(fù)數(shù)怎么表示研究出來(lái)的迫卢。正數(shù)的表示方法都是統(tǒng)一的,負(fù)數(shù)的數(shù)值和正數(shù)的數(shù)值表示方法一樣的方式就是原碼冶共、負(fù)數(shù)是正數(shù)各位取反的表示方式就叫反碼乾蛤、負(fù)數(shù)是正數(shù)各位取反再補(bǔ)上個(gè)1的表示方式就叫補(bǔ)碼
(3)原碼的形式可以很直觀(guān)的表示出負(fù)數(shù),所以在書(shū)面書(shū)寫(xiě)時(shí)捅僵,一般用原碼家卖,比如編程,但是因?yàn)橛?jì)算問(wèn)題庙楚,計(jì)算機(jī)存儲(chǔ)的時(shí)候都是存儲(chǔ)的補(bǔ)碼上荡,計(jì)算機(jī)只管存儲(chǔ),計(jì)算,不在意是否是正數(shù)酪捡,負(fù)數(shù)叁征。正負(fù)是由編譯器和操作系統(tǒng)自己的規(guī)則決定的。