由IEEE 754深入理解浮點(diǎn)數(shù)

??本文又臭又長(zhǎng)恕沫,實(shí)用價(jià)值不大养晋。只是小碼農(nóng)最近腦子抽風(fēng)突然想搞明白為什么0.1+0.2=0.30000000000000004才查閱資料寫的殷蛇。嫌浪費(fèi)時(shí)間者可以不看...
??在說這個(gè)問題之前倔监,我們先看兩個(gè)常識(shí)批旺。第一個(gè)是n位二進(jìn)制能最大表示的無(wú)符號(hào)整數(shù)销睁?這個(gè)大家應(yīng)該都知道是20 + 21 + … + 2n-1供璧,即2n – 1。第二個(gè)是二進(jìn)制的科學(xué)計(jì)數(shù)法(這是為了之后好分析冻记,小碼農(nóng)自創(chuàng)的一種說法)睡毒。小學(xué)我們就知道十進(jìn)制中有一個(gè)科學(xué)計(jì)數(shù)法,即如825.25會(huì)被表示成8.2525 * 102冗栗。那么在二進(jìn)制的世界中也可以有一個(gè)科學(xué)計(jì)數(shù)法演顾。如8.25在二進(jìn)制被表示為1010.01供搀,寫成科學(xué)計(jì)數(shù)法就可以表示成1.01001 * 23。120.5在二進(jìn)制中為1110110.1钠至,寫成科學(xué)計(jì)數(shù)法就是1.1101101 * 26葛虐。所以是不是發(fā)現(xiàn)在二進(jìn)制的科學(xué)計(jì)數(shù)法中浮點(diǎn)數(shù)可以被表示成如1.xxx * 2t的形式呢。而事實(shí)上也如此棉钧,計(jì)算機(jī)內(nèi)部表示一個(gè)浮點(diǎn)數(shù)會(huì)將其分成三個(gè)部分:符號(hào)位(0為正屿脐、1位負(fù)。記為S)宪卿、尾數(shù)部分(1.xxx的诵。記xxx部分為M)和指數(shù)部分(2t。記t為E)佑钾。所以二進(jìn)制的科學(xué)計(jì)數(shù)法就是: (-1)S * (1.M) * 2E奢驯。
??明白這兩個(gè)概念之后我們就可以來(lái)解釋Java浮點(diǎn)數(shù)的表示范圍了。首先Java使用的浮點(diǎn)數(shù)運(yùn)算規(guī)則是IEEE 754次绘。那么什么是IEEE 754呢?簡(jiǎn)單的說就是一個(gè)美國(guó)定義的被廣泛采用的浮點(diǎn)數(shù)運(yùn)算標(biāo)準(zhǔn)撒遣。再按照上段的格式可得邮偎,在32位的float中分配規(guī)則為:1位符號(hào)位(S)、8位指數(shù)位(E)义黎、23位尾數(shù)位(M)禾进。在64位的double中為:1位符號(hào)位(S)、 11位指數(shù)位(E)廉涕、52位尾數(shù)位(M)泻云。
??我們剛才說到的二進(jìn)制的科學(xué)計(jì)數(shù)法為(-1)S * (1.M) * 2E。這個(gè)其實(shí)是不準(zhǔn)確的狐蜕,為什么不準(zhǔn)確呢宠纯?請(qǐng)繼續(xù)看下去。
??大家都知道在一串連續(xù)的二進(jìn)制位中想正數(shù)和負(fù)數(shù)都表示出來(lái)一般采用的方法是在最高位加一個(gè)符號(hào)位层释。但是這樣在運(yùn)算的時(shí)候就需要采用補(bǔ)碼進(jìn)行運(yùn)算婆瓜。比如在4bit的情況下-5的二進(jìn)制表示為1101,+4的二進(jìn)制表示為0100贡羔。直接使用原碼進(jìn)行相加后得到的值為10001廉白,竟然直接溢出了!換算成補(bǔ)碼后-5的補(bǔ)碼為1011乖寒,+4的補(bǔ)碼為0100猴蹂,運(yùn)算后再轉(zhuǎn)換為原碼可得1001,恰是-1楣嘁。即符號(hào)位會(huì)造成限制的磅轻。
??所以由以上所有解釋可得:n位二進(jìn)制位能表示的范圍為:[-2n-1 , 2n-1-1]珍逸,也就是說在E中還有一位符號(hào)位。但I(xiàn)EEE 754并沒有采用這種存儲(chǔ)方式瓢省,而是采用了無(wú)符號(hào)數(shù)值減去一個(gè)偏正值的形式來(lái)存儲(chǔ)整數(shù)弄息。即若指數(shù)部分存儲(chǔ)的為00000111,實(shí)際上表示的是:00000111 – 偏正值勤婚。偏正值為2n-1-1摹量。這種方式被稱為指數(shù)偏差。為什么呢馒胆?我們不妨考慮一個(gè)情況缨称,在需要對(duì)指數(shù)部分做比較時(shí),-5和-4做比較祝迂,符號(hào)位相同睦尽,其他位從高至低誰(shuí)先為0誰(shuí)較大,但+5和+4作比較型雳,符號(hào)位相同当凡,其他位從高至低誰(shuí)先為1誰(shuí)較大。這兩種比較方式恰是相反的纠俭,在硬件上更難實(shí)現(xiàn)沿量。既然這樣,那為什么還需要存在符號(hào)位呢冤荆,不如都使用這種指數(shù)偏差的形式朴则?小碼農(nóng)認(rèn)為這是由于IEEE 754僅規(guī)定了四種精度的浮點(diǎn)數(shù),偏正值都是相對(duì)固定的钓简。而對(duì)于任意n位二進(jìn)制位的數(shù)值來(lái)說乌妒,采用指數(shù)偏差的形式存儲(chǔ)每次都需要計(jì)算偏正值,時(shí)間效率上是難以接受的外邓。
??這個(gè)時(shí)候我們就會(huì)發(fā)現(xiàn)若指數(shù)位為8位撤蚊,則采用了指數(shù)偏移形式來(lái)存儲(chǔ)的指數(shù)部分實(shí)際表達(dá)的數(shù)值為[-127, 128]。我靠坐榆,這竟然違反客觀事實(shí)了拴魄!哈哈哈,其實(shí)不是這樣子的席镀,IEEE 954規(guī)定指數(shù)部分在區(qū)間[1, 2n-2]中才時(shí)減去偏正值匹中。那么0和2n-1該怎么處理呢?這個(gè)我們等下再分析『阑澹現(xiàn)在更新二進(jìn)制形式的科學(xué)計(jì)數(shù)法為(-1)S * (1.M) * 2E-偏正值顶捷。
??解釋完指數(shù)位之后,尾數(shù)位就很好理解了屎篱,就是n位二進(jìn)制位表示的無(wú)符號(hào)整數(shù)服赎,區(qū)間為[0, 2n-1]】伲現(xiàn)在我們就可以求出浮點(diǎn)數(shù)的范圍了。

  • float(32位):1位符號(hào)位(S)重虑、8位指數(shù)位(E)践付、23位尾數(shù)位(M)。
    ???S的取值范圍:0或1缺厉; ?????? E的取值范圍:[1, 254] 永高;
    ???M取值范圍:[0, 223-1]; ?? 偏正值:127
  • double(64位):1位符號(hào)位(S)提针、11位指數(shù)位(E)命爬、52位尾數(shù)位(M)。
    ???S的取值范圍:0或1辐脖; ??????E的取值范圍:[1, 2046]饲宛;
    ???M取值范圍:[0, 252-1];?? 偏正值:1023

??其實(shí)說到這里我們一直在解釋的都是規(guī)格形式的浮點(diǎn)數(shù)嗜价。也就是E的取值區(qū)間為 [1, 2n-2]且尾數(shù)的整數(shù)部分為1的情況艇抠。那么,對(duì)于超出這個(gè)限定的情況會(huì)如何處理呢久锥?如果大家對(duì)學(xué)過高級(jí)程序設(shè)計(jì)語(yǔ)言會(huì)知道练链,一般某個(gè)數(shù)值類中會(huì)有無(wú)窮大、NAN(Not A Number)這種特殊的情況奴拦,如Java中的Double.NAN,Double.NEGATIVE_INFINITY届吁、Double.POSITIVE_INFINITY错妖。而其實(shí)超出這個(gè)限定的部分是被用來(lái)處理特殊情況的。
??有了規(guī)格化浮點(diǎn)數(shù)疚沐,肯定還有非規(guī)格化浮點(diǎn)數(shù)暂氯。但注意:非規(guī)格化值域和規(guī)格化值域不是互補(bǔ)的,除了這兩種還有特殊值亮蛔!定義非規(guī)格式浮點(diǎn)數(shù)的E為0痴施,尾數(shù)非零且尾數(shù)的整數(shù)部分為0。這樣的話其實(shí)它就不符合科學(xué)計(jì)數(shù)法的形式了究流,但我們?nèi)匀话纯茖W(xué)計(jì)數(shù)法的形式來(lái)表達(dá)辣吃。在IEEE 954標(biāo)準(zhǔn)中規(guī)定除了規(guī)格化情況下之外的其他所有情況偏移后的值為規(guī)格情況下偏移后再加1。
??呵呵芬探,看到這里有人不禁的發(fā)出一聲冷笑神得。IEEE 754是有病啊,弄的這么惡心偷仿。其實(shí)不是這樣的哩簿,這樣做是為了解決“突然式下溢出”而誕生的(維基百科說是INTEL力薦的)宵蕉。咱們先來(lái)看看不采用IEEE 754標(biāo)準(zhǔn)所產(chǎn)生的一種惡果。假如不采用 IEEE 754节榜,E最小可以取0羡玛,以正單精度浮點(diǎn)數(shù)舉例。最小規(guī)格浮點(diǎn)數(shù)為2-127宗苍,次小規(guī)格浮點(diǎn)數(shù)為2-127 * (1 + 2-23)稼稿。它倆之間的差值為2-127 * 2-23(此時(shí)是最小差值)。而最小規(guī)格浮點(diǎn)數(shù)與0之間的差值為2-127浓若。就會(huì)出現(xiàn)一種情況渺杉,兩個(gè)相近的不相等的規(guī)格浮點(diǎn)數(shù)做差值時(shí)可能得到的數(shù)值在0和最小規(guī)格浮點(diǎn)數(shù)之間,這是不能被真實(shí)表示出來(lái)的情況挪钓,就會(huì)出現(xiàn)突然下降至0的情況是越。但如果采用了IEEE 754,最小和次小規(guī)格浮點(diǎn)數(shù)之間的差值為2-126 * 2-23碌上,但在2-126至0之間還有能被實(shí)際表示出來(lái)的浮點(diǎn)數(shù)倚评。我們不妨來(lái)求一下最小的非規(guī)格浮點(diǎn)數(shù):2-126 * 2-23。恰好等于最小相鄰規(guī)格浮點(diǎn)數(shù)之差馏予。所以這種神奇的規(guī)定是為了解決“突然式下溢出”的情況天梧。
??這時(shí)候,大家肯定有一個(gè)疑問霞丧,無(wú)論采不采用IEEE 754呢岗,能表示的范圍都是一定的,為什么會(huì)有這種區(qū)分呢蛹尝?實(shí)際上就像我們推導(dǎo)出來(lái)的float和double范圍后豫,超出這個(gè)范圍的都被認(rèn)為是非法的情況。在被規(guī)定為合法的精度范圍內(nèi)做運(yùn)算時(shí)不會(huì)發(fā)生錯(cuò)誤突那。
??除了規(guī)格化浮點(diǎn)數(shù)和非規(guī)格化浮點(diǎn)數(shù)挫酿,IEEE 954還規(guī)定了幾種特殊值。不過我們先看看這兩種非特殊值能表示的最大最小值(僅舉正數(shù))愕难。從下圖這張表中也可以看出非規(guī)格化浮點(diǎn)數(shù)的絕對(duì)值小于所有的規(guī)格化浮點(diǎn)數(shù)的絕對(duì)值早龟。

規(guī)格化 非規(guī)格化
最大 E=254,M=223-1猫缭,S=0
(2-2-23) * 2127
E=0葱弟,M=223-1,S=0
((1-2-23) * 2-126
最小 E=-126猜丹,M=0翘悉,S=0
(2-126
E=0,M=1居触,S=0
(2-23 * 2-126

??說完了主要的部分妖混,我們就可以來(lái)看看最后這些特殊情況了老赤。(單精度為例)

類型 E M S
正無(wú)窮 255 0 0 +∞
負(fù)無(wú)窮 255 0 1 -∞
NAN 255 非零 * NAN

??講到這里,理論部分已經(jīng)全部結(jié)束了制市。下面用Java來(lái)證明一下抬旺。(注:Java中是雙精度的,數(shù)據(jù)不一致祥楣,但道理一致)

測(cè)試
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末开财,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子误褪,更是在濱河造成了極大的恐慌责鳍,老刑警劉巖,帶你破解...
    沈念sama閱讀 207,113評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件兽间,死亡現(xiàn)場(chǎng)離奇詭異历葛,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)嘀略,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門恤溶,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人帜羊,你說我怎么就攤上這事咒程。” “怎么了讼育?”我有些...
    開封第一講書人閱讀 153,340評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵帐姻,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我奶段,道長(zhǎng)卖宠,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,449評(píng)論 1 279
  • 正文 為了忘掉前任忧饭,我火速辦了婚禮,結(jié)果婚禮上筷畦,老公的妹妹穿的比我還像新娘词裤。我一直安慰自己,他們只是感情好鳖宾,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,445評(píng)論 5 374
  • 文/花漫 我一把揭開白布吼砂。 她就那樣靜靜地躺著,像睡著了一般鼎文。 火紅的嫁衣襯著肌膚如雪渔肩。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,166評(píng)論 1 284
  • 那天拇惋,我揣著相機(jī)與錄音周偎,去河邊找鬼抹剩。 笑死,一個(gè)胖子當(dāng)著我的面吹牛蓉坎,可吹牛的內(nèi)容都是我干的澳眷。 我是一名探鬼主播,決...
    沈念sama閱讀 38,442評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼蛉艾,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼钳踊!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起勿侯,我...
    開封第一講書人閱讀 37,105評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤拓瞪,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后助琐,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體祭埂,經(jīng)...
    沈念sama閱讀 43,601評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,066評(píng)論 2 325
  • 正文 我和宋清朗相戀三年弓柱,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了沟堡。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,161評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡矢空,死狀恐怖航罗,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情屁药,我是刑警寧澤粥血,帶...
    沈念sama閱讀 33,792評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站酿箭,受9級(jí)特大地震影響复亏,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜缭嫡,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,351評(píng)論 3 307
  • 文/蒙蒙 一缔御、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧妇蛀,春花似錦耕突、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至纵诞,卻和暖如春上祈,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評(píng)論 1 261
  • 我被黑心中介騙來(lái)泰國(guó)打工登刺, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留籽腕,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,618評(píng)論 2 355
  • 正文 我出身青樓塘砸,卻偏偏與公主長(zhǎng)得像节仿,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子掉蔬,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,916評(píng)論 2 344

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