1.為什么用補(bǔ)碼
首先肯定一點(diǎn)筑煮,計(jì)算機(jī)中非浮點(diǎn)數(shù)(浮點(diǎn)數(shù)沒(méi)研究過(guò))都是用補(bǔ)碼表示二進(jìn)制數(shù)的,為什么用補(bǔ)碼而不用原碼或者反碼粤蝎,是因?yàn)檠a(bǔ)碼系統(tǒng)的最大優(yōu)點(diǎn)是可以在加法或減法處理中真仲,不需因?yàn)閿?shù)字的正負(fù)而使用不同的計(jì)算方式。只要一種加法電路就可以處理各種有號(hào)數(shù)加法初澎,而且減法可以用一個(gè)數(shù)加上另一個(gè)數(shù)的補(bǔ)碼來(lái)表示秸应,因此只要有加法電路及補(bǔ)碼電路即可完成各種有號(hào)數(shù)加法及減法,在電路設(shè)計(jì)上相當(dāng)方便碑宴。減法電路得設(shè)計(jì)相對(duì)而言更復(fù)雜软啼。
2. 為什么補(bǔ)碼可以實(shí)現(xiàn)減法
要想理解這一點(diǎn),首先必須知道同余的概念延柠。想象一個(gè)時(shí)鐘祸挪,如下圖
現(xiàn)在是8點(diǎn)鐘,如果我想時(shí)間變到6點(diǎn)中贞间,那么我有兩種方法贿条,第一種順時(shí)針10個(gè)小時(shí)雹仿,第二種逆時(shí)針旋轉(zhuǎn)2個(gè)小時(shí),都可以得到6點(diǎn)鐘整以。但是就本質(zhì)而言胧辽,這兩種方法得到的6點(diǎn)鐘,其實(shí)是不同的公黑。如果8點(diǎn)是上午8點(diǎn)邑商,那么第一鐘方法得到的其實(shí)是下午的6點(diǎn),但第二鐘方法得到的是上午的6點(diǎn)凡蚜。但是對(duì)于這個(gè)表而言人断,它只有1點(diǎn)到12點(diǎn),并沒(méi)有上午下午之分番刊,對(duì)于它而言含鳞,這兩張方法得到的都是6點(diǎn)鐘(時(shí)鐘指針都是指向6),并沒(méi)有區(qū)別芹务。
換成計(jì)算的方式蝉绷,第一中方式相當(dāng)于8+10=186,第二種方式相當(dāng)于8-2=6枣抱。
在這個(gè)時(shí)鐘的例子里熔吗,一個(gè)時(shí)鐘最多只能表示12個(gè)小時(shí),即從1點(diǎn)到12點(diǎn)佳晶。上例中的8點(diǎn)加十個(gè)小時(shí)桅狠,計(jì)算結(jié)果是18時(shí),但是時(shí)鐘最多只能表示12時(shí)轿秧,這種情況下就是溢出了中跌,超出了時(shí)鐘能表示的范圍,最后結(jié)果是6點(diǎn)菇篡。
那么在這種情況情況下的加減運(yùn)算都是模12的加減運(yùn)算漩符,12就是時(shí)鐘能表示的數(shù)字范圍。而同余表示兩個(gè)數(shù)除以12驱还,余數(shù)相同嗜暴,稱之為同余,用表示议蟆。這個(gè)概念以及符號(hào)最早是高斯提出來(lái)的闷沥,果然是個(gè)偉人。
3.補(bǔ)碼的計(jì)算
當(dāng)你查閱資料時(shí)咐容,尤其是用百度(程序員還是用google好)舆逃,你會(huì)發(fā)現(xiàn)大部分人寫(xiě)的補(bǔ)碼的計(jì)算方法都是:符號(hào)位不變,其他位取反,末位加1颖侄。也就是說(shuō)要算補(bǔ)碼鸟雏,先拿到反碼享郊。這里補(bǔ)充一下原碼览祖、反碼、補(bǔ)碼的知識(shí)炊琉。原碼就是二進(jìn)制數(shù)展蒂,比如2,用8位二進(jìn)制就是0000 0010苔咪,那反碼就是加入符號(hào)位(0表示正數(shù)锰悼,1表示復(fù)數(shù)),最高位表示符號(hào)位团赏,比如-2箕般,用8位二進(jìn)制就是1000 0010,最后補(bǔ)碼舔清,比如-2丝里,就是-2的符號(hào)位不變,其他位組為取反体谒,即1111 1101杯聚,然后末位加1,即1111 1110抒痒。正數(shù)的原碼反碼補(bǔ)碼相等幌绍,都是原碼。
但是如果你感興趣故响,自己琢磨傀广,你會(huì)發(fā)現(xiàn)有個(gè)特殊的數(shù)字0,按照上述的方法計(jì)算會(huì)糾結(jié)彩届,0的原碼是0000 0000伪冰,反碼是1000 0000,如果除符號(hào)位逐位取反惨缆,即1111 1111糜值,再加1的話,會(huì)產(chǎn)生進(jìn)位坯墨,這個(gè)進(jìn)位寂汇,要不要進(jìn)給符號(hào)位,如果給捣染,那就是0000 0000骄瓣,如果不給,那這個(gè)進(jìn)位浪費(fèi)掉耍攘,最后是1000榕栏,0000畔勤。而實(shí)際的結(jié)果是多少呢,是0000 0000扒磁,符號(hào)位參與運(yùn)算庆揪。而也就是說(shuō)0的補(bǔ)碼還是0。而這個(gè)1000 0000其實(shí)也是有特殊用途的(后面說(shuō))妨托。在整個(gè)補(bǔ)碼的計(jì)算過(guò)程中缸榛,只有計(jì)算0的補(bǔ)碼會(huì)產(chǎn)生溢出。
上面說(shuō)了0計(jì)算的補(bǔ)碼還是0兰伤,其實(shí)還有一個(gè)特殊的補(bǔ)碼内颗,即1000 0000,這個(gè)補(bǔ)碼敦腔,你找不到原碼均澳,不信你找找看。
其實(shí)如果你想得多符衔,你會(huì)發(fā)現(xiàn)這兩個(gè)特殊的數(shù)找前。就拿8位的二進(jìn)制來(lái)說(shuō),能表示256個(gè)數(shù)柏腻。如果按照上述說(shuō)的補(bǔ)碼來(lái)表示的話纸厉,正數(shù)能表示0-127,剛好128個(gè)數(shù)五嫂,256的一半颗品,那么負(fù)數(shù)必然也能表示另外一半,難道是(-0)-(-127)沃缘?很明顯躯枢,-0是沒(méi)有的,因?yàn)?的補(bǔ)碼還是0槐臀,那么(-1)-(-127)只有127個(gè)數(shù)锄蹂,剩下一個(gè)是什么?就是那個(gè)無(wú)法計(jì)算補(bǔ)碼的數(shù)1000 0000水慨。既然(-0)沒(méi)意義得糜,那么這個(gè)多出來(lái)的數(shù)就表示-128,這樣剛好不浪費(fèi)晰洒。(補(bǔ)一句朝抖,如果用反碼表示,那還真的有-0谍珊,等于浪費(fèi)一個(gè)數(shù))治宣。這個(gè)現(xiàn)象如果你寫(xiě)代碼一定能發(fā)現(xiàn),比如java的int類型或者long類型,最小負(fù)數(shù)的絕對(duì)值一定比最大正數(shù)大1侮邀,不信你試試看坏怪。
上述的計(jì)算補(bǔ)碼的方式其實(shí)說(shuō)復(fù)雜了,簡(jiǎn)單的方法是直接逐位取反绊茧,末位加1即可铝宵。而且這個(gè)反過(guò)來(lái)也可以,即知道補(bǔ)碼求原碼按傅,也能這樣算捉超。
補(bǔ)碼的計(jì)算為什么是逐位取反,末位加1唯绍,拿8位二進(jìn)制舉例,其最大能表示=256個(gè)數(shù)枝誊,那么一個(gè)數(shù)逐位取反后况芒,這個(gè)取反后的數(shù)和原數(shù)相加必定等于257,比如1001 0010叶撒,逐位取反后绝骚,是0110 1101,這兩個(gè)數(shù)相加一定是1111 1111祠够,即257压汪,再加上1,就是258古瓤。所以一個(gè)數(shù)的補(bǔ)碼的計(jì)算可以概括為一下公式止剖,如果一個(gè)數(shù)是a,二進(jìn)制位數(shù)是n落君,那么補(bǔ)碼就是
-a穿香。
現(xiàn)在,如果你已知一個(gè)補(bǔ)碼b绎速,讓你求原碼皮获,你怎么計(jì)算,按照逐位取反纹冤,末位加1的反向計(jì)算可不可以洒宝,當(dāng)然可以,先減一萌京,再逐位取反(符號(hào)位不變)雁歌。但是如果你將上面的那段推理看明白的話,其實(shí)同樣按照逐位取反枫夺,末尾加1的計(jì)算方式即可将宪。(回頭看看那個(gè)無(wú)法求原碼的補(bǔ)碼1000 0000,按照逐位取反,末位加1较坛,得到的還是1000 0000)
這個(gè)模型就是a+b=印蔗,那么a=
-b,b=
-a丑勤。
4 補(bǔ)碼的同余
對(duì)于一般的計(jì)算华嘹,a的補(bǔ)碼我們認(rèn)為是-a,為什么可以這樣法竞。對(duì)于a耙厚,根據(jù)計(jì)算公式,其補(bǔ)碼為-a岔霸,我們需要認(rèn)定的是-a與
-a同余即可薛躬。
-a=-a-(*(-1))...
-a,即商取-1呆细,得到余數(shù)是
-a
對(duì)于-a型宝,商取0即可,得到余數(shù)是自身絮爷,與-a的余數(shù)相同趴酣,得到 -a
-a
從而用這種方式計(jì)算補(bǔ)碼,表示負(fù)數(shù)坑夯。(對(duì)于負(fù)數(shù)取余岖寞,各個(gè)語(yǔ)言有些差異,主要在取商上面柜蜈,請(qǐng)看參考文檔)
以上仗谆,我們得出結(jié)論,a的補(bǔ)碼即為-a
5 運(yùn)算
補(bǔ)碼只是解決兩數(shù)相減的運(yùn)算跨释,對(duì)于兩正數(shù)相加胸私,兩負(fù)數(shù)相減的溢出問(wèn)題,任然還是問(wèn)題鳖谈。也就是說(shuō)溢出了岁疼,就超出了能計(jì)算的范圍,答案就是錯(cuò)的缆娃。
觀察一下補(bǔ)碼的運(yùn)算捷绒,一個(gè)正數(shù)減去另一個(gè)正數(shù),或者說(shuō)一個(gè)正數(shù)加上一個(gè)負(fù)數(shù)贯要。對(duì)于補(bǔ)碼暖侨,以8位舉例,最大的數(shù)-1崇渗,是1111 1111字逗,最小的數(shù)-128京郑,是1000 0000,我們看葫掉,最大的數(shù)是最容易溢出些举,溢出后表示的就是正數(shù),而計(jì)算結(jié)果也正是正數(shù)俭厚。而最小的數(shù)反而是最不容易溢出的户魏,那相加的數(shù)沒(méi)溢出,表示的數(shù)還是負(fù)數(shù)挪挤。
6 番外
注意叼丑,8位二進(jìn)制能表示256個(gè)數(shù)是沒(méi)有質(zhì)疑的,但是能表示哪256個(gè)數(shù)扛门,卻是人為定義的鸠信。
比如負(fù)數(shù),表示(-1)-(-128)很容易理解尖飞,但是症副,根據(jù)上面的同余概念,(-1)與(-257)同余政基,
(-128)與(-384)同余。那么闹啦,負(fù)數(shù)部分表示(-257)-(-384)可不可以沮明?當(dāng)然可以,但是
正數(shù)部分表示的數(shù)也得相應(yīng)改變(由(0)-(127)變?yōu)?256)-(383))窍奋,這樣才能保證計(jì)算結(jié)果結(jié)果正確荐健。
參考資料:
https://zh.wikipedia.org/wiki/%E4%BA%8C%E8%A3%9C%E6%95%B8
http://ceeji.net/blog/mod-in-real/