一氛赐、整數(shù)在計(jì)算機(jī)中的表示
在C/C++中,整數(shù)一般分為無符號數(shù)(unsigned char先舷、unsigned short艰管、unsigned int等)和有符號數(shù)(char、short蒋川、int牲芋、long等),在計(jì)算機(jī)中通過補(bǔ)碼來表示捺球,那么有童鞋會問了缸浦,不是有那什么原碼、反碼之類的嗎氮兵?為什么不用它們而偏偏用補(bǔ)碼呢裂逐?
一開始我也有這樣的困惑,于是通過各種查泣栈,各種看卜高,算是理解了一點(diǎn)點(diǎn),這里不打算詳細(xì)解釋原碼和反碼南片,只舉幾個例子說明在計(jì)算機(jī)中為什么不用它們表示十進(jìn)制數(shù)掺涛,而用補(bǔ)碼來表示。
我們能認(rèn)識0疼进、1薪缆、2、3伞广、拣帽、、9等自然數(shù)赔癌,然而計(jì)算機(jī)卻不認(rèn)識诞外,計(jì)算機(jī)“笨”的只認(rèn)識0和1澜沟,所以那些大神們就通過各種手段灾票,將現(xiàn)實(shí)世界中的各種信息都轉(zhuǎn)化為一連串由0和1組成的序列。然后計(jì)算機(jī)就通過不同的解讀方式茫虽,對這一系列的01串串根據(jù)具體的上下文解釋成不同的信息刊苍。
我們都知道1 + (-1) = 0
,那么如果用原碼濒析、反碼來表示這個會怎樣呢正什?
原碼:
原碼 十進(jìn)制
0000 0001 1
+ 1000 0001 -1
----------------
1000 0010 -2
反碼:
反碼 十進(jìn)制
0000 0001 1
+ 1111 1110 -1
----------------
1111 1111 -0 // 需要通過轉(zhuǎn)換為原碼,才能直觀的看出所表示的實(shí)際數(shù)字号杏,原碼:1000 0000
通過上面兩個例子婴氮,我們看到斯棒,不管是用原碼還是反碼,都不能正確的表達(dá)結(jié)果主经。另外荣暮,我們可以發(fā)現(xiàn),在原碼和反碼中罩驻,對于0的表示有兩種穗酥,一種是0000 0000
(+0),一種是1000 0000
(-0)惠遏,這也是一種缺陷砾跃,最好的方式是在給定一個十進(jìn)制整數(shù)的范圍內(nèi),該范圍內(nèi)的每一個數(shù)在相應(yīng)的二進(jìn)制表示中有且只有一個與之對應(yīng)节吮,也就是存在一一映射的關(guān)系抽高。那么如何解決上述的問題呢?
終于等到補(bǔ)碼登場了透绩,一般主角都壓軸厨内,哈哈。補(bǔ)碼渺贤,就是在反碼的基礎(chǔ)上再加1雏胃,比如-1的補(bǔ)碼就是1111 1110
+ 1
= 1111 1111
,用補(bǔ)碼來進(jìn)行上面的計(jì)算就是:
反碼 十進(jìn)制
0000 0001 1
+ 1111 1111 -1
----------------
1 0000 0000 0 // 最高位的1被丟棄
結(jié)果為0志鞍,符合我們的實(shí)際邏輯瞭亮。我們再來看看前面提到的一一映射的問題,在C/C++中固棚,char
表示一個8bit的有符號整數(shù)统翩,在計(jì)算機(jī)中用補(bǔ)碼表示,所能表示的十進(jìn)制范圍為[-128, 127]
共256個數(shù)此洲,那么這個范圍是怎么得來的呢厂汗?
補(bǔ)碼 十進(jìn)制
0000 0000 0
0000 0001 1
...
...
...
0111 1111 127(2^7 - 1)
1000 0000 -128(-2^7 + 0)
1000 0001 -127(-2^7 + 1)
...
...
...
1111 1111 -1(-2^7 + 127)
從上面可以看出,前128個數(shù)表示正數(shù)(最高位以0開始)呜师,后128個表示負(fù)數(shù)(最高位以1開始)娶桦。對于unsigned char
來說,由于其為無符號數(shù)汁汗,所以所能表示的最大范圍為[0, 255]
衷畦。對于其它的整數(shù)數(shù)據(jù)類型可以通過類似的方法得到他們的表示范圍,感興趣的童鞋可以自己算算試試知牌。
二祈争、小數(shù)在計(jì)算機(jī)中的表示
對于float
來說,在一般機(jī)器上都是以四個字節(jié)即32bit來表示角寸,那么它在計(jì)算機(jī)中是怎么表示的呢菩混?
IEEE 754規(guī)定忿墅,對于32位的浮點(diǎn)數(shù),最高位的那位表示符號位s
沮峡,緊接著的8位是指數(shù)E
球匕,剩下的23位為有效數(shù)字M
或者稱為尾數(shù)。
在十進(jìn)制中帖烘,對于任何一個小數(shù)都可以用科學(xué)計(jì)數(shù)法來表示亮曹,比如123.567
的科學(xué)計(jì)數(shù)法就是1.23456*10^2
,0.0097
就是9.7*10^-3
秘症;同樣地照卦,在二進(jìn)制的世界中,任何一個小數(shù)也可以用類似的科學(xué)技術(shù)法來表示乡摹,只不過不在以10
為底役耕,而是以2
為底。那么對于十進(jìn)制的123.567
和0.0097
在二進(jìn)制中如何表示呢聪廉?
十進(jìn)制小數(shù):123.567
在二進(jìn)制中的表示:
1. 首先取整數(shù)部分123瞬痘,用二進(jìn)制中表示為1111011。
2. 小數(shù)部分.567如何表示板熊?
我們都知道框全,在十進(jìn)制整數(shù)進(jìn)行二進(jìn)制轉(zhuǎn)化的時候有一個方法,就是對十進(jìn)制數(shù)進(jìn)行不斷的除以2干签,然后取余數(shù)(要么為0津辩,要么為1),然后按逆序排列就得到了十進(jìn)制整數(shù)的二進(jìn)制表示容劳。
那么對于十進(jìn)制的小數(shù)該如何用二進(jìn)制表示是否找到了靈感喘沿?對,就是對小數(shù)部分不斷的乘以2竭贩,然后對得到的新小數(shù)取整數(shù)部分(要么為0蚜印,要么為1)直到小數(shù)部分為0或者已經(jīng)達(dá)到精度上限(比如所取得0、1已經(jīng)達(dá)到23位了留量,再繼續(xù)乘下去窄赋,對于32位的float來說,已經(jīng)不能繼續(xù)存儲了)肪获。
0.567 * 2 = 1.134 …… 取1 寝凌, 基數(shù) = 0.134
0.134 * 2 = 0.268 …… 取0 柒傻, 基數(shù) = 0.268
0.268 * 2 = 0.563 …… 取0 孝赫, 基數(shù) = 0.563
0.563 * 2 = 1.126 …… 取1 , 基數(shù) = 0.126
……
……
……
最終結(jié)果為:10010001001001101110100红符。(23位)
所以.567在二進(jìn)制中的表示為:.10010001001001101110100青柄。
因而123.567在二進(jìn)制中的表示為:1111011.10010001001001101110100伐债。
用科學(xué)計(jì)數(shù)法表示為:1.1110 1110 0100 0100 1001 1011 1010 0 * 2^6。
通過IEEE 754的規(guī)定致开,我們可以很容易將其在計(jì)算機(jī)中表示:
符號位:0
指數(shù)位:Exp - 127 = 6 --> Exp = 133 -->1000 0101
尾數(shù)部分:1110 1110 0100 0100 1001 101
【IEEE 754規(guī)定峰锁,在計(jì)算機(jī)內(nèi)部保存M時(1.XXXXXXX),默認(rèn)這個數(shù)的第一位總是1双戳,因此可以被舍去虹蒋,只保存后面的xxxxxx部分§酰】
所以123.567在計(jì)算機(jī)中的完整表示就是:
0 1000 0101 1110 1110 0100 0100 1001 101
通過在線工具魄衅,可以驗(yàn)證上面結(jié)果的正確性,如下圖:
對于0.0097
也可以用同樣的方法得到其在計(jì)算機(jī)內(nèi)部的表示塘辅,這里就不在贅述了晃虫,有興趣的童鞋可以自己嘗試一下,然后通過上面提到的在線工具驗(yàn)證一下扣墩。
這里稍微再提一下哲银,在C/C++中,float
所能保持的精度一般為小數(shù)位6-7位呻惕,那么這個6或7是怎么得來的呢荆责?通過上面我們知道,對于32位的浮點(diǎn)數(shù)亚脆,后23位表示的是小數(shù)部分草巡,總共可以表示2^23 = 8388608
,也就是說型酥,后面的23位最多可以表示十進(jìn)制小數(shù)的前7位小數(shù)位山憨,通過四舍五入,至少可以保證6位的精度是正確的弥喉,至于第7位......呵呵郁竟!
好了,通過上面的描述由境,基本了解了float
在計(jì)算機(jī)內(nèi)存是如何表示的了棚亩,那么double
在計(jì)算機(jī)中如何表示呢?其實(shí)和float
的表示原理是一樣的虏杰,只是double
一般用64位bit來表示讥蟆,最高位還是符號位,但是指數(shù)部分用了11位來表示纺阔,而剩余的52位全用來表示尾數(shù)(所能表示的精度一般為2^52 = 瘸彤?
15-16位),其余的規(guī)則和32位的float
沒啥區(qū)別笛钝,所以這里就僅放一張圖质况,各位童鞋可以慢慢去體會愕宋。
后記
這是我在簡書上發(fā)表的第一篇文章,希望自己能一直堅(jiān)持下去结榄,養(yǎng)成一個習(xí)慣中贝。
對于文章中的不足之處,懇請各位讀者批評指正臼朗。
簡書給我的感覺就是三個字 -- 簡潔邻寿、美。
感謝這個平臺视哑。