《Java編程的邏輯》筆記9--小數(shù)的二進制表示

小數(shù)的二進制表示.png

小數(shù)計算為什么會出錯膝晾?

簡要答案
實際上栓始,不是運算本身會出錯,而是計算機根本就不能精確的表示很多數(shù)血当,比如0.1這個數(shù)幻赚。
計算機是用一種二進制格式存儲小數(shù)的,這個二進制格式不能精確表示0.1臊旭,它只能表示一個非常接近0.1但又不等于0.1的一個數(shù)落恼。

數(shù)字都不能精確表示,在不精確數(shù)字上的運算結(jié)果不精確也就不足為奇了离熏。

0.1怎么會不能精確表示呢佳谦?在十進制的世界里是可以的,但在二進制的世界里不行滋戳。在說二進制之前钻蔑,我們先來看下熟悉的十進制。

實際上奸鸯,十進制也只能表示那些可以表述為10的多少次方和的數(shù)咪笑,比如12.345,實際上表示的:110+21+30.1+40.01+5*0.001娄涩,與整數(shù)的表示類似窗怒,小數(shù)點后面的每個位置也都有一個位權(quán),從左到右蓄拣,依次為 0.1,0.01,0.001,...即10^(-1), 10^(-2), 10^(-3)扬虚。

很多數(shù),十進制也是不能精確表示的球恤,比如1/3, 保留三位小數(shù)的話辜昵,十進制表示是0.333,但無論后面保留多少位小數(shù)咽斧,都是不精確的路鹰,用0.333進行運算贷洲,比如乘以3,期望結(jié)果是1晋柱,但實際上卻是0.999优构。

二進制是類似的,但二進制只能表示哪些可以表述為2的多少次方和的數(shù)雁竞,來看下2的次方的一些例子:


image.png

可以精確表示為2的某次方之和的數(shù)可以精確表示钦椭,其他數(shù)則不能精確表示。

為什么一定要用二進制呢碑诉?

為什么就不能用我們熟悉的十進制呢彪腔?在最最底層,計算機使用的電子元器件只能表示兩個狀態(tài)进栽,通常是低壓和高壓德挣,對應(yīng)0和1,使用二進制容易基于這些電子器件構(gòu)建硬件設(shè)備和進行運算快毛。如果非要使用十進制格嗅,則這些硬件就會復(fù)雜很多,并且效率低下唠帝。

為什么有的小數(shù)計算是準(zhǔn)確的

如果你編寫程序進行試驗屯掖,你會發(fā)現(xiàn)有的計算結(jié)果是準(zhǔn)確的。比如襟衰,我用Java寫:

System.out.println(0.1f+0.1f);  

System.out.println(0.1f*0.1f);

第一行輸出0.2贴铜,第二行輸出0.010000001。按照上面的說法瀑晒,第一行的結(jié)果應(yīng)該也不對吧馨印?

其實苔悦,這只是Java語言給我們造成的假象轩褐,計算結(jié)果其實也是不精確的,但是由于結(jié)果和0.2足夠接近间坐,在輸出的時候,Java選擇了輸出0.2這個看上去非常精簡的數(shù)字邑退,而不是一個中間有很多0的小數(shù)竹宋。

在誤差足夠小的時候,結(jié)果看上去是精確的地技,但不精確其實才是常態(tài)蜈七。

怎么處理計算不精確

計算不精確,怎么辦呢莫矗?大部分情況下飒硅,我們不需要那么高的精度砂缩,可以四舍五入,或者在輸出的時候只保留固定個數(shù)的小數(shù)位三娩。

如果真的需要比較高的精度庵芭,一種方法是將小數(shù)轉(zhuǎn)化為整數(shù)進行運算,運算結(jié)束后再轉(zhuǎn)化為小數(shù)雀监,另外的方法一般是使用十進制的數(shù)據(jù)類型双吆,這個沒有統(tǒng)一的規(guī)范,在Java中是BigDecimal会前,運算更準(zhǔn)確好乐,但效率比較低,本節(jié)就不詳細說了瓦宜。

二進制表示

我們之前一直在用"小數(shù)"這個詞表示float和double類型蔚万,其實,這是不嚴謹?shù)模?小數(shù)"是在數(shù)學(xué)中用的詞临庇,在計算機中反璃,我們一般說的是"浮點數(shù)"。float和double被稱為浮點數(shù)據(jù)類型苔巨,小數(shù)運算被稱為浮點運算版扩。

為什么要叫浮點數(shù)呢?這是由于小數(shù)的二進制表示中侄泽,表示那個小數(shù)點的時候礁芦,點不是固定的,而是浮動的悼尾。

我們還是用10進制類比柿扣,10進制有科學(xué)表示法,比如123.45這個數(shù)闺魏,直接這么寫未状,就是固定表示法,如果用科學(xué)表示法析桥,在小數(shù)點前只保留一位數(shù)字司草,可以寫為1.2345E2即1.2345*(10^2),即在科學(xué)表示法中泡仗,小數(shù)點向左浮動了兩位埋虹。

二進制中為表示小數(shù),也采用類似的科學(xué)表示法娩怎,形如 m*(2^e)搔课。m稱為尾數(shù),e稱為指數(shù)截亦。指數(shù)可以為真爬泥,也可以為負柬讨,負的指數(shù)表示哪些接近0的比較小的數(shù)。在二進制中袍啡,單獨表示尾數(shù)部分和指數(shù)部分踩官,另外還有一個符號位表示正負。

幾乎所有的硬件和編程語言表示小數(shù)的二進制格式都是一樣的葬馋,這種格式是一個標(biāo)準(zhǔn)卖鲤,叫做IEEE 754標(biāo)準(zhǔn),它定義了兩種格式畴嘶,一種是32位的蛋逾,對應(yīng)于Java的float,另一種是64位的窗悯,對應(yīng)于Java的double区匣。

32位格式中,1位表示符號蒋院,23位表示尾數(shù)亏钩,8位表示指數(shù)。64位格式中欺旧,1位表示符號姑丑,52位表示尾數(shù),11位表示指數(shù)辞友。

在兩種格式中栅哀,除了表示正常的數(shù),標(biāo)準(zhǔn)還規(guī)定了一些特殊的二進制形式表示一些特殊的值称龙,比如負無窮留拾,正無窮,0鲫尊,NaN (非數(shù)值痴柔,比如0乘以無窮大)。

IEEE 754標(biāo)準(zhǔn)有一些復(fù)雜的細節(jié)疫向,初次看上去難以理解咳蔚,對于日常應(yīng)用也不常用,本文就不介紹了搔驼。

如果你想查看浮點數(shù)的具體二進制形式移斩,在Java中寝优,可以使用如下代碼:

Integer.toBinaryString(Float.floatToIntBits(value))
Long.toBinaryString(Double.doubleToLongBits(value));

寫在最后

都看到這里酒甸,保存思維導(dǎo)圖礁叔,順便給個贊唄

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末妄荔,一起剝皮案震驚了整個濱河市泼菌,隨后出現(xiàn)的幾起案子谍肤,更是在濱河造成了極大的恐慌,老刑警劉巖哗伯,帶你破解...
    沈念sama閱讀 222,729評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件荒揣,死亡現(xiàn)場離奇詭異,居然都是意外死亡焊刹,警方通過查閱死者的電腦和手機系任,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,226評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來虐块,“玉大人俩滥,你說我怎么就攤上這事『氐欤” “怎么了霜旧?”我有些...
    開封第一講書人閱讀 169,461評論 0 362
  • 文/不壞的土叔 我叫張陵,是天一觀的道長儡率。 經(jīng)常有香客問我挂据,道長,這世上最難降的妖魔是什么儿普? 我笑而不...
    開封第一講書人閱讀 60,135評論 1 300
  • 正文 為了忘掉前任崎逃,我火速辦了婚禮,結(jié)果婚禮上眉孩,老公的妹妹穿的比我還像新娘个绍。我一直安慰自己,他們只是感情好勺像,可當(dāng)我...
    茶點故事閱讀 69,130評論 6 398
  • 文/花漫 我一把揭開白布障贸。 她就那樣靜靜地躺著,像睡著了一般吟宦。 火紅的嫁衣襯著肌膚如雪篮洁。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,736評論 1 312
  • 那天殃姓,我揣著相機與錄音袁波,去河邊找鬼。 笑死蜗侈,一個胖子當(dāng)著我的面吹牛篷牌,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播踏幻,決...
    沈念sama閱讀 41,179評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼枷颊,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起夭苗,我...
    開封第一講書人閱讀 40,124評論 0 277
  • 序言:老撾萬榮一對情侶失蹤信卡,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后题造,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體傍菇,經(jīng)...
    沈念sama閱讀 46,657評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,723評論 3 342
  • 正文 我和宋清朗相戀三年界赔,在試婚紗的時候發(fā)現(xiàn)自己被綠了丢习。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,872評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡淮悼,死狀恐怖咐低,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情袜腥,我是刑警寧澤渊鞋,帶...
    沈念sama閱讀 36,533評論 5 351
  • 正文 年R本政府宣布,位于F島的核電站瞧挤,受9級特大地震影響锡宋,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜特恬,卻給世界環(huán)境...
    茶點故事閱讀 42,213評論 3 336
  • 文/蒙蒙 一执俩、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧癌刽,春花似錦役首、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,700評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至远荠,卻和暖如春矮固,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背譬淳。 一陣腳步聲響...
    開封第一講書人閱讀 33,819評論 1 274
  • 我被黑心中介騙來泰國打工档址, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人邻梆。 一個月前我還...
    沈念sama閱讀 49,304評論 3 379
  • 正文 我出身青樓守伸,卻偏偏與公主長得像,于是被迫代替她去往敵國和親浦妄。 傳聞我的和親對象是個殘疾皇子尼摹,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,876評論 2 361

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