浮點型數(shù)據(jù)丟失精度的原因

ackage test1;

public class Test2 {

/**

* @param args

*/

public static void main(String[] args) {

Float xx = 2.0f;

Float yy = 1.8f;

Float tt = xx - yy;

System.out.println("tttttt-----" + tt);

}

}

果然輸出結(jié)果是: tttttt-----0.20000005

再測試了幾個float類型的減法英妓,除了*.0這樣的相減沒有異議之外,都存在這個問題灭翔,就是說float在相減的時候精度丟失了甸祭。后來在網(wǎng)上找到一段解決這個問題的辦法卤唉,記在這里:

package test1;

import java.math.BigDecimal;

public class Test2 {

/**

* @param args

*/

public static void main(String[] args) {

Float xx = 2.2f;

Float yy = 2.0f;

Float tt = xx - yy;

BigDecimal b1 = new BigDecimal(Float.toString(xx));

BigDecimal b2 = new BigDecimal(Float.toString(yy));

float ss = b1.subtract(b2).floatValue();

System.out.println("ssss----" + ss);

System.out.println("tttttt-----" + tt);

}

}

輸出為:

ssss----0.2

tttttt-----0.20000005

這樣一對比,差異就很明顯了沟于。

解決了問題吏廉,再找了一下為什么會產(chǎn)生這種差異:

網(wǎng)上有篇文章寫得很詳細,標題為《剖析float型的內(nèi)存存儲和精度丟失問題》效扫,全文內(nèi)容如下:

問題提出:12.0f-11.9f=0.10000038倔监,"減不盡"為什么?

現(xiàn)在我們就詳細剖析一下浮點型運算為什么會造成精度丟失荡短?

1丐枉、小數(shù)的二進制表示問題

首先我們要搞清楚下面兩個問題:

(1) 十進制整數(shù)如何轉(zhuǎn)化為二進制數(shù)

算法很簡單。舉個例子掘托,11表示成二進制數(shù):

11/2=5 余??? 1

5/2=2??? 余??? 1

2/2=1??? 余??? 0

1/2=0??? 余??? 1

0結(jié)束????????? 11二進制表示為(從下往上):1011

這里提一點:只要遇到除以后的結(jié)果為0了就結(jié)束了瘦锹,大家想一想,所有的整數(shù)除以2是不是一定能夠最終得到0闪盔。換句話說弯院,所有的整數(shù)轉(zhuǎn)變?yōu)槎M制數(shù)的算法會不會無限循環(huán)下去呢?絕對不會泪掀,整數(shù)永遠可以用二進制精確表示听绳,但小數(shù)就不一定了。

(2) 十進制小數(shù)如何轉(zhuǎn)化為二進制數(shù)

算法是乘以2直到?jīng)]有了小數(shù)為止异赫。舉個例子椅挣,0.9表示成二進制數(shù)

0.9*2=1.8??? 取整數(shù)部分 1

0.8(1.8的小數(shù)部分)*2=1.6???? 取整數(shù)部分 1

0.6*2=1.2??? 取整數(shù)部分 1

0.2*2=0.4??? 取整數(shù)部分 0

0.4*2=0.8??? 取整數(shù)部分 0

0.8*2=1.6 取整數(shù)部分 1

0.6*2=1.2??? 取整數(shù)部分 0

.........?????? 0.9二進制表示為(從上往下): 1100100100100......

注意:上面的計算過程循環(huán)了,也就是說*2永遠不可能消滅小數(shù)部分塔拳,這樣算法將無限下去鼠证。很顯然,小數(shù)的二進制表示有時是不可能精確的靠抑。其實道理很簡單量九,十進制系統(tǒng)中能不能準確表示出1/3呢?同樣二進制系統(tǒng)也無法準確表示1/10颂碧。這也就解釋了為什么浮點型減法出現(xiàn)了"減不盡"的精度丟失問題荠列。

2、float型在內(nèi)存中的存儲

眾所周知载城、Java 的float型在內(nèi)存中占4個字節(jié)肌似。float的32個二進制位結(jié)構(gòu)如下

float內(nèi)存存儲結(jié)構(gòu)

4bytes ????? 31 ??? 30 ??? 29----23 ??? 22----0

表示??????? 實數(shù)符號位 ??? 指數(shù)符號位???????? 指數(shù)位?????????? 有效數(shù)位

其中符號位1表示正,0表示負诉瓦。有效位數(shù)位24位锈嫩,其中一位是實數(shù)符號位受楼。

將一個float型轉(zhuǎn)化為內(nèi)存存儲格式的步驟為:

(1)先將這個實數(shù)的絕對值化為二進制格式,注意實數(shù)的整數(shù)部分和小數(shù)部分的二進制方法在上面已經(jīng)探討過了呼寸。

(2)將這個二進制格式實數(shù)的小數(shù)點左移或右移n位,直到小數(shù)點移動到第一個有效數(shù)字的右邊猴贰。

(3)從小數(shù)點右邊第一位開始數(shù)出二十三位數(shù)字放入第22到第0位对雪。

(4)如果實數(shù)是正的,則在第31位放入“0”米绕,否則放入“1”瑟捣。

(5)如果n 是左移得到的,說明指數(shù)是正的栅干,第30位放入“1”迈套。如果n是右移得到的或n=0,則第30位放入“0”碱鳞。

(6)如果n是左移得到的桑李,則將n減去1后化為二進制,并在左邊加“0”補足七位窿给,放入第29到第23位贵白。如果n是右移得到的或n=0,則將n化為二進制后在左邊加“0”補足七位崩泡,再各位求反禁荒,再放入第29到第23位。

舉例說明: 11.9的內(nèi)存存儲格式

(1) 將11.9化為二進制后大約是"1011.1110011001100110011001100..."角撞。

(2) 將小數(shù)點左移三位到第一個有效位右側(cè):"1.01111100110011001100110"呛伴。保證有效位數(shù)24位,右側(cè)多余的截融怂(誤差在這里產(chǎn)生了)热康。

(3)這已經(jīng)有了二十四位有效數(shù)字,將最左邊一位“1”去掉百炬,得到“01111100110011001100110”共23bit褐隆。將它放入float存儲結(jié)構(gòu)的第22到第0位。

(4) 因為11.9是正數(shù)剖踊,因此在第31位實數(shù)符號位放入“0”庶弃。

(5) 由于我們把小數(shù)點左移,因此在第30位指數(shù)符號位放入“1”德澈。

(6) 因為我們是把小數(shù)點左移3位歇攻,因此將3減去1得2,化為二進制梆造,并補足7位得到0000010缴守,放入第29到第23位葬毫。

最后表示11.9為:01000001001111100110011001100110

再舉一個例子:0.2356的內(nèi)存存儲格式

(1)將0.2356化為二進制后大約是0.00111100010100000100100000。

(2)將小數(shù)點右移三位得到1.11100010100000100100000屡穗。

(3)從小數(shù)點右邊數(shù)出二十三位有效數(shù)字贴捡,即11100010100000100100000放

入第22到第0位。

(4)由于0.2356是正的村砂,所以在第31位放入“0”烂斋。

(5)由于我們把小數(shù)點右移了,所以在第30位放入“0”础废。

(6)因為小數(shù)點被右移了3位汛骂,所以將3化為二進制,在左邊補“0”補足七

位评腺,得到0000011帘瞭,各位取反,得到1111100蒿讥,放入第29到第23位蝶念。

最后表示0.2356為:00111110011100010100000100100000

將一個內(nèi)存存儲的float二進制格式轉(zhuǎn)化為十進制的步驟:

(1)將第22位到第0位的二進制數(shù)寫出來,在最左邊補一位“1”诈悍,得到二十四位有效數(shù)字祸轮。將小數(shù)點點在最左邊那個“1”的右邊。

(2)取出第29到第23位所表示的值n侥钳。當30位是“0”時將n各位求反适袜。當30位是“1”時將n增1。

(3)將小數(shù)點左移n位(當30位是“0”時)或右移n位(當30位是“1”時)舷夺,得到一個二進制表示的實數(shù)苦酱。

(4)將這個二進制實數(shù)化為十進制,并根據(jù)第31位是“0”還是“1”加上正號或負號即可给猾。

3疫萤、浮點型的減法運算

浮點加減運算過程比定點運算過程復(fù)雜。完成浮點加減運算的操作過程大體分為四步:

(1) 0操作數(shù)的檢查敢伸;

如果判斷兩個需要加減的浮點數(shù)有一個為0扯饶,即可得知運算結(jié)果而沒有必要再進行有序的一些列操作。

(2) 比較階碼(指數(shù)位)大小并完成對階池颈;

兩浮點數(shù)進行加減尾序,首先要看兩數(shù)的指數(shù)位是否相同,即小數(shù)點位置是否對齊躯砰。若兩數(shù)指數(shù)位相同每币,表示小數(shù)點是對齊的,就可以進行尾數(shù)的加減運算琢歇。反之兰怠,若兩數(shù)階碼不同梦鉴,表示小數(shù)點位置沒有對齊,此時必須使兩數(shù)的階碼相同揭保,這個過程叫做對階肥橙。

如何對階(假設(shè)兩浮點數(shù)的指數(shù)位為Ex和 Ey):

通過尾數(shù)的移位以改變 Ex或 Ey,使之相等掖举。由? ? ? ? ? ? 于浮點表示的數(shù)多是規(guī)格化的快骗,尾數(shù)左移會引起最高有位的丟失,造成很大誤差塔次;而尾數(shù)右移雖引起最低有效位的丟失,但造成的誤差較小名秀,因此励负,對階操作規(guī)定使? ? ? ? ? ? 尾數(shù)右移,尾數(shù)右移后使階碼作相應(yīng)增加匕得,其數(shù)值保持不變继榆。很顯然,一個增加后的階碼與另一個相等汁掠,所增加的階碼一定是小階略吨。因此在對階時,總是使小階向大階看齊考阱,即小階的尾數(shù)向右移位( 相當于小數(shù)點左移 ) 翠忠,每右移一位,其階碼加 1 乞榨,直到兩數(shù)的階碼相等為止秽之,右移的位數(shù)等于階差 △E。

(3) 尾數(shù)(有效數(shù)位)進行加或減運算吃既;

對階完畢后就可 有效數(shù)位 求和考榨。 不論是加法運算還是減法運算,都按加法進行操作鹦倚,其方法與定點加減運算完全一樣河质。

(4) 結(jié)果規(guī)格化并進行舍入處理。

4震叙、 計算12.0f-11.9f

12.0f 的內(nèi)存存儲格式為:01000001010000000000000000000000

11.9f 的內(nèi)存存儲格式為:01000001001111100110011001100110

可見兩數(shù)的指數(shù)位完全相同掀鹅,只要對有效數(shù)位進行減法即可。

12.0f-11.9f??? 結(jié)果:01000001000000011001100110011010

將結(jié)果還原為十進制為: 0.00011001100110011010=0.10000038


轉(zhuǎn)自:http://www.blogjava.net/jelver/articles/340038.html

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末捐友,一起剝皮案震驚了整個濱河市淫半,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌匣砖,老刑警劉巖科吭,帶你破解...
    沈念sama閱讀 211,423評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件昏滴,死亡現(xiàn)場離奇詭異,居然都是意外死亡对人,警方通過查閱死者的電腦和手機谣殊,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,147評論 2 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來牺弄,“玉大人姻几,你說我怎么就攤上這事∈聘妫” “怎么了蛇捌?”我有些...
    開封第一講書人閱讀 157,019評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長咱台。 經(jīng)常有香客問我络拌,道長,這世上最難降的妖魔是什么回溺? 我笑而不...
    開封第一講書人閱讀 56,443評論 1 283
  • 正文 為了忘掉前任春贸,我火速辦了婚禮,結(jié)果婚禮上遗遵,老公的妹妹穿的比我還像新娘萍恕。我一直安慰自己,他們只是感情好车要,可當我...
    茶點故事閱讀 65,535評論 6 385
  • 文/花漫 我一把揭開白布允粤。 她就那樣靜靜地躺著,像睡著了一般屯蹦。 火紅的嫁衣襯著肌膚如雪维哈。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,798評論 1 290
  • 那天登澜,我揣著相機與錄音阔挠,去河邊找鬼。 笑死脑蠕,一個胖子當著我的面吹牛购撼,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播谴仙,決...
    沈念sama閱讀 38,941評論 3 407
  • 文/蒼蘭香墨 我猛地睜開眼迂求,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了晃跺?” 一聲冷哼從身側(cè)響起揩局,我...
    開封第一講書人閱讀 37,704評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎掀虎,沒想到半個月后凌盯,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體付枫,經(jīng)...
    沈念sama閱讀 44,152評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,494評論 2 327
  • 正文 我和宋清朗相戀三年驰怎,在試婚紗的時候發(fā)現(xiàn)自己被綠了阐滩。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,629評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡县忌,死狀恐怖掂榔,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情症杏,我是刑警寧澤装获,帶...
    沈念sama閱讀 34,295評論 4 329
  • 正文 年R本政府宣布,位于F島的核電站厉颤,受9級特大地震影響饱溢,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜走芋,卻給世界環(huán)境...
    茶點故事閱讀 39,901評論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望潘鲫。 院中可真熱鬧翁逞,春花似錦、人聲如沸溉仑。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,742評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽浊竟。三九已至怨喘,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間振定,已是汗流浹背必怜。 一陣腳步聲響...
    開封第一講書人閱讀 31,978評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留后频,地道東北人梳庆。 一個月前我還...
    沈念sama閱讀 46,333評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像卑惜,于是被迫代替她去往敵國和親膏执。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,499評論 2 348

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