計算機是怎么存儲數(shù)字的

從一個最簡單的例子開始吧。

我們來做幾個小學(xué)生的加法題衩匣。8 + 9 等于多少擂仍?0.8 + 0.9 等于多少?在 Chrome 里面簡單用 Javascript 這門語言簡單測試一下笑跛,我們得到的結(jié)果是:
8 + 9 = 17
0.8 + 0.9 = 1.7000000000000002付魔。
是的,你沒有看錯飞蹂,計算機給出了 1.7000000000000002 這個答案几苍。難道計算機錯了嗎?

計算機錯了陈哑,又沒錯妻坝。為什么呢?因為計算機是用二進(jìn)制來表示這些數(shù)字的惊窖,有很多數(shù)在計算機里面是沒法精確表示的刽宪。先來看看什么是二進(jìn)制。

十進(jìn)制界酒、二進(jìn)制

我們都知道圣拄,計算機只能懂 0 和 1,也就是說計算機里面所有的數(shù)字毁欣,都是二進(jìn)制形式的庇谆。那么一個普通的數(shù)字岳掐,用二進(jìn)制的形式究竟該如何表示呢?譬如:

  • 78 如何使用二進(jìn)制表示饭耳?

對于正整數(shù)串述,數(shù)學(xué)上有一個轉(zhuǎn)換的公式,就是「除 2 取余寞肖,逆序排列」法剖煌。具體做法是:用 2 整除十進(jìn)制整數(shù),可以得到一個商和余數(shù)逝淹;再用 2 去除商耕姊,又會得到一個商和余數(shù),如此進(jìn)行栅葡,直到商為 0 時為止茉兰,然后把先得到的余數(shù)作為二進(jìn)制數(shù)的低位有效位,后得到的余數(shù)作為二進(jìn)制數(shù)的高位有效位欣簇,依次排列起來规脸。對于 78 這個十進(jìn)制整數(shù)來說,對應(yīng)的二進(jìn)制是 1001110.

  • 0.5 如何使用二進(jìn)制表示熊咽?

對于純小數(shù)莫鸭,也有一個固定的轉(zhuǎn)換法:乘 2 取整,順序排列横殴。具體做法就是:用 2 乘十進(jìn)制小數(shù)被因,可以得到積,將積的整數(shù)部分取出衫仑,再用 2 乘余下的小數(shù)部分梨与,又得到一個積,再將積的整數(shù)部分取出文狱,如此進(jìn)行粥鞋,直到積中的小數(shù)部分為零,此時 0 或 1 為二進(jìn)制的最后一位瞄崇。對于十進(jìn)制的 0.5 來說呻粹,對應(yīng)的二進(jìn)制表示就是 0.1

  • 8.5 如何使用二進(jìn)制表示?

好了苏研,有零有整的小數(shù)等浊,在計算機里面怎么表示呢?可能大家已經(jīng)知道了楣富,分成整數(shù)和純小數(shù)兩部分凿掂,分別轉(zhuǎn)換,然后相加起來。那么 8.5 的二進(jìn)制形式可以表示為:1000.1

好了庄萎,這是基礎(chǔ)踪少,后面的內(nèi)容就開始慢慢接近計算機的工作模式了。

二進(jìn)制能準(zhǔn)確表示十進(jìn)制數(shù)字嗎

首先看這個問題:

  • 0.1 這個小數(shù)糠涛,用二進(jìn)制該如何表示

按照前面的轉(zhuǎn)換規(guī)則援奢,我們先看看看 0.1 怎么表示:
0.1 * 2 = 0.2 ---- 0 (1)
0.2 * 2 = 0.4 ---- 0 (2)
0.4 * 2 = 0.8 ---- 0 (3)
0.8 * 2 = 1.6 ---- 1 (4)
0.6 * 2 = 1.2 ---- 1 (5)
0.2 * 2 = 0.4 ---- 0 (6)

算到這里,我們得到了 0.000110 這樣的一段二進(jìn)制串忍捡,但是不能再算下去了集漾,因為我們看到第 6 行和第 2 行完全一樣,再計算就一直循環(huán)下去了砸脊。所以具篇,0.1 這樣一個十進(jìn)制小數(shù),在計算機的二進(jìn)制里面根本沒法精確表示凌埂。

思考一下驱显,0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9 這 9 個小數(shù),有幾個是可以精確表示的瞳抓?

  • 精確表示 Vs 精確顯示

通過前面的代碼我們知道埃疫,0.8 + 0.9 的結(jié)果,計算機并不能精確表示孩哑,但是我們在 Javascript 中定義這樣一個數(shù)值變量

var ha = 1.7

在控制臺打印的話栓霜,結(jié)果又確實是 1.7。

好像很矛盾横蜒。顯然胳蛮,通過后面的例子可以知道 Javascript 可以精確顯示 1.7(哪怕 1.7 不能被精確表示),這不是和最開始我們的結(jié)果矛盾嗎愁铺?

其實這是一個想當(dāng)然的錯誤鹰霍。在直觀上我們認(rèn)為 0.8 + 0.9 = 1.7 是必然成立的(數(shù)學(xué)上確實如此),而且 1.7 又能被精確顯示茵乱,那最開始的結(jié)果就應(yīng)該等于 1.7,對不對孟岛?

而實際上瓶竭,在計算機里 0.8 + 0.9 根本不等于 1.7(什么?)渠羞!因為 0.8 和 0.9 都不能被精確表示斤贰,數(shù)值的精度丟失在了每一個環(huán)節(jié),而不是最后的結(jié)果上次询。

我們可以用數(shù)學(xué)中四舍五入的概念類比一下荧恍。我們計算 1.6 + 2.8 保留整數(shù),我們覺得結(jié)果應(yīng)該是 4(4.4 舍入)。但是我們用另一種方法:先把 1.6 舍入成 2送巡,再把 2.8 舍入成 3摹菠,最后得到 5。通過不同的運算骗爆,我們得到了完全不一樣的結(jié)果次氨!所以,在 0.8 + 0.9 的運算中摘投,參與運算的兩個數(shù)精度一開始已經(jīng)丟失了煮寡,所以他們的結(jié)果也不再是 1.7 了。

看到這里犀呼,我們是不是要懷疑計算機的一切結(jié)果了幸撕?連幾個小數(shù)都無法精確表示的話,其他數(shù)值計算結(jié)果如何保證準(zhǔn)確呢外臂?其實杈帐,大家不用擔(dān)心,計算機在做浮點運算的時候专钉,常常會因為無法精確表示而進(jìn)行近似或舍入挑童,而其結(jié)果在我們?nèi)粘I钏璧木确秶鷥?nèi),都還是準(zhǔn)確的跃须。

剛才說到了浮點運算站叼,照字面的理解就是浮點數(shù)的運算了。但是菇民,浮點數(shù)是什么呢尽楔?計算機里面是怎么表示這些數(shù)字的呢?

浮點數(shù)是什么

為了弄清楚浮點數(shù)第练,我們需要先看定點數(shù)阔馋。所謂定點數(shù),是計算機中采用的一種數(shù)的表示方法娇掏,參與運算的數(shù)的小數(shù)點位置固定不變呕寝。那么小數(shù)點位置可變的自然就是所謂的「浮點數(shù)」了。這里要先澄清一個概念:浮點數(shù)并不一定等于小數(shù)婴梧,定點數(shù)也并不一定就是整數(shù)下梢;整數(shù)和小數(shù)是我們小學(xué)數(shù)學(xué)中使用的,在計算機的世界里塞蹭,只有定點數(shù)和浮點數(shù)孽江。

  • 定點整數(shù)

小數(shù)點位固定在最后一位之后稱為定點整數(shù)。若機器字長為 8 位番电,那么它能表示的整數(shù)范圍是 -127 - 127(考慮正負(fù)數(shù)的符號)岗屏。例如 0111 表示 7。

  • 定點小數(shù)

小數(shù)點固定在最高位之后稱為定點小數(shù)。若機器字長為 8 位这刷,數(shù)值表示范圍是[-(1-2^(-7)), 1-2^(-7)]婉烟。例如 1111 表示 -0.875。

  • 浮點數(shù)

在計算機的硬件中是沒有小數(shù)點這個東西的崭歧。CPU 能處理的東西都是整的隅很。所以,小數(shù)就要用類似科學(xué)計數(shù)法的方式來表示率碾。如 1.234 在計算機里面叔营,可以理解成用 1234 和 -3 兩個整數(shù)來表示:1234 * 10 的 -3 次方,這類數(shù)就叫「浮點數(shù)」所宰。當(dāng)然绒尊,計算機里面的浮點數(shù)是二進(jìn)制的。任意一個二進(jìn)制浮點數(shù) V 都可以表示成下面的形式:

V = (-1)^s x M x 2^E

這里:

  1. (-1)^s 表示符號位仔粥,當(dāng)s = 0婴谱,V 為正數(shù);當(dāng) s = 1躯泰,V 為負(fù)數(shù)谭羔;
  2. M 表示有效數(shù)字,必須大于等于 1麦向、小于 2瘟裸;
  3. 2^E 表示指數(shù)位。

舉例來說诵竭,十進(jìn)制的 5.0话告,寫成二進(jìn)制是 101.0,相當(dāng)于 1.01 x 2^2卵慰。那么按照上面的格式沙郭,可以得出 s = 0, M = 1.01, E = 2。

CPU 在處理這類數(shù)的運算時需要比整數(shù)運算復(fù)雜得多的電路設(shè)計裳朋,且速度比整數(shù)運算慢很多(所以很多年前病线,浮點運算能力是衡量 CPU 性能的重要指標(biāo))。

浮點數(shù)的更多問題

歷史上計算機科學(xué)家們曾提出過多種解決方案再扭,最終獲得廣泛應(yīng)用的是 IEEE 754 標(biāo)準(zhǔn)中的方案氧苍。IEEE 754 規(guī)定,對于 32 位的浮點數(shù)泛范,最高的 1 位是符號位 s,接著的 8 位是指數(shù) E紊撕,剩下的 23 位為有效數(shù)字 M:

32 位浮點數(shù)的分段表示

IEEE 754 對有效數(shù)字 M 和指數(shù) E罢荡,還有一些特別規(guī)定。

前面說過,1≤M<2区赵,也就是說惭缰,M 可以寫成 1.xxxxxx 的形式,其中 xxxxxx 表示小數(shù)部分笼才。IEEE 754 規(guī)定漱受,在計算機內(nèi)部保存 M 時,默認(rèn)這個數(shù)的第一位總是 1骡送,因此可以被舍去昂羡,只保存后面的 xxxxxx 部分。比如保存 1.01 的時候摔踱,只保存 01虐先,等到讀取的時候,再把第一位的 1 加上去派敷。這樣做的目的蛹批,是節(jié)省 1 位有效數(shù)字。以 32 位浮點數(shù)為例篮愉,留給 M 只有 23 位腐芍,將第一位的 1 舍去以后,等于可以保存 24 位有效數(shù)字试躏。

至于指數(shù) E猪勇,情況就比較復(fù)雜。

首先冗酿,E 是沒有符號的埠对。這意味著,如果 E 為 8 位裁替,它的取值范圍為 0~255项玛;但是,我們知道弱判,科學(xué)計數(shù)法中的 E 是可以出現(xiàn)負(fù)數(shù)的襟沮,所以 IEEE 754 規(guī)定,E 的真實值必須再減去一個中間數(shù)(偏移值)昌腰。IEEE 754 標(biāo)準(zhǔn)規(guī)定該固定值為 2^(E-1) - 1开伏,對于 8 位的 E,這個中間數(shù)是 127遭商。

比如固灵,2^10 的 E 是 10,所以保存成 32 位浮點數(shù)時劫流,必須保存成10+127=137巫玻,即 10001001丛忆。

然后,指數(shù) E 還可以再分成三種情況:

  1. E不全為 0 或不全為 1仍秤。這時熄诡,浮點數(shù)就采用上面的規(guī)則表示,即指數(shù) E 的計算值減去 127诗力,得到真實值凰浮,再將有效數(shù)字 M 前加上第一位的 1;
  2. E全為 0。這時苇本,浮點數(shù)的指數(shù) E 等于 1-127袜茧,有效數(shù)字 M 不再加上第一位的 1,而是還原為 0.xxxxxx 的小數(shù)圈澈。這樣做是為了表示 ±0惫周,以及接近于 0 的很小的數(shù)字;
  3. E 全為 1。這時如果有效數(shù)字 M 全為0康栈,表示 ±無窮大(正負(fù)取決于符號位s)递递;如果有效數(shù)字M不全為0,表示這個數(shù)不是一個數(shù)(NaN)

浮點數(shù)表示范圍與表示個數(shù)
對于計算機來說啥么,浮點數(shù)可表示的范圍相當(dāng)大登舞,但這并不等于表示個數(shù)。從數(shù)量級分析一下悬荣,32bit 浮點數(shù)的表示范圍是 10 的 38 次方菠秒,而表示個數(shù)呢,是 10 的 10 次方氯迂。 能夠被表示的數(shù)只有 1/100000000…. (大概有30個零)践叠。

總之,計算機中數(shù)字的存儲嚼蚀、表示禁灼、計算是非常復(fù)雜的,涉及到的內(nèi)容轿曙,都夠單獨出一本大部頭的書了弄捕,大家有興趣可以自己找資料深入研究一下。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末导帝,一起剝皮案震驚了整個濱河市守谓,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌您单,老刑警劉巖斋荞,帶你破解...
    沈念sama閱讀 217,406評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異虐秦,居然都是意外死亡譬猫,警方通過查閱死者的電腦和手機讯檐,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,732評論 3 393
  • 文/潘曉璐 我一進(jìn)店門羡疗,熙熙樓的掌柜王于貴愁眉苦臉地迎上來染服,“玉大人,你說我怎么就攤上這事叨恨×危” “怎么了?”我有些...
    開封第一講書人閱讀 163,711評論 0 353
  • 文/不壞的土叔 我叫張陵痒钝,是天一觀的道長秉颗。 經(jīng)常有香客問我,道長送矩,這世上最難降的妖魔是什么蚕甥? 我笑而不...
    開封第一講書人閱讀 58,380評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮栋荸,結(jié)果婚禮上菇怀,老公的妹妹穿的比我還像新娘。我一直安慰自己晌块,他們只是感情好爱沟,可當(dāng)我...
    茶點故事閱讀 67,432評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著匆背,像睡著了一般呼伸。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上钝尸,一...
    開封第一講書人閱讀 51,301評論 1 301
  • 那天括享,我揣著相機與錄音,去河邊找鬼珍促。 笑死铃辖,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的踢星。 我是一名探鬼主播澳叉,決...
    沈念sama閱讀 40,145評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼沐悦!你這毒婦竟也來了成洗?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,008評論 0 276
  • 序言:老撾萬榮一對情侶失蹤藏否,失蹤者是張志新(化名)和其女友劉穎瓶殃,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體副签,經(jīng)...
    沈念sama閱讀 45,443評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡遥椿,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,649評論 3 334
  • 正文 我和宋清朗相戀三年基矮,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片冠场。...
    茶點故事閱讀 39,795評論 1 347
  • 序言:一個原本活蹦亂跳的男人離奇死亡家浇,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出碴裙,到底是詐尸還是另有隱情钢悲,我是刑警寧澤,帶...
    沈念sama閱讀 35,501評論 5 345
  • 正文 年R本政府宣布舔株,位于F島的核電站莺琳,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏载慈。R本人自食惡果不足惜惭等,卻給世界環(huán)境...
    茶點故事閱讀 41,119評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望办铡。 院中可真熱鬧辞做,春花似錦、人聲如沸料扰。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,731評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽晒杈。三九已至嫂伞,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間拯钻,已是汗流浹背帖努。 一陣腳步聲響...
    開封第一講書人閱讀 32,865評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留粪般,地道東北人拼余。 一個月前我還...
    沈念sama閱讀 47,899評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像亩歹,于是被迫代替她去往敵國和親匙监。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,724評論 2 354

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