日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) >

float 精度_float相加产生精度损失的原因是什么?

發(fā)布時(shí)間:2025/3/20 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 float 精度_float相加产生精度损失的原因是什么? 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

float f0 = 0.021f;
float f1 = 0.022f;
out.println(f0);
out.println(f1);
out.println(f0 + f1);
結(jié)果:
0.021
0.022
0.042999998
為什么不是0.043?

Java Float類型 減法運(yùn)算時(shí)精度丟失問(wèn)題?www.blogjava.net

package 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

再測(cè)試了幾個(gè)float類型的減法,除了*.0這樣的相減沒(méi)有異議之外,都存在這個(gè)問(wèn)題,就是說(shuō)float在相減的時(shí)候精度丟失了。后來(lái)在網(wǎng)上找到一段解決這個(gè)問(wèn)題的辦法,記在這里:

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

這樣一對(duì)比,差異就很明顯了。

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

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

問(wèn)題提出:12.0f-11.9f=0.10000038,"減不盡"為什么?

現(xiàn)在我們就詳細(xì)剖析一下浮點(diǎn)型運(yùn)算為什么會(huì)造成精度丟失?

1、小數(shù)的二進(jìn)制表示問(wèn)題

首先我們要搞清楚下面兩個(gè)問(wèn)題:

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

算法很簡(jiǎn)單。舉個(gè)例子,11表示成二進(jìn)制數(shù):

11/2=5 余 1

5/2=2 余 1

2/2=1 余 0

1/2=0 余 1

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

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

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

算法是乘以2直到?jīng)]有了小數(shù)為止。舉個(gè)例子,0.9表示成二進(jìn)制數(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二進(jìn)制表示為(從上往下): 1100100100100......

注意:上面的計(jì)算過(guò)程循環(huán)了,也就是說(shuō)*2永遠(yuǎn)不可能消滅小數(shù)部分,這樣算法將無(wú)限下去。很顯然,小數(shù)的二進(jìn)制表示有時(shí)是不可能精確的 。其實(shí)道理很簡(jiǎn)單,十進(jìn)制系統(tǒng)中能不能準(zhǔn)確表示出1/3呢?同樣二進(jìn)制系統(tǒng)也無(wú)法準(zhǔn)確表示1/10。這也就解釋了為什么浮點(diǎn)型減法出現(xiàn)了"減不盡"的精度丟失問(wèn)題。

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

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

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

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

表示 實(shí)數(shù)符號(hào)位 指數(shù)符號(hào)位 指數(shù)位 有效數(shù)位

其中符號(hào)位1表示正,0表示負(fù)。有效位數(shù)位24位,其中一位是實(shí)數(shù)符號(hào)位。

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

(1)先將這個(gè)實(shí)數(shù)的絕對(duì)值化為二進(jìn)制格式,注意實(shí)數(shù)的整數(shù)部分和小數(shù)部分的二進(jìn)制方法在上面已經(jīng)探討過(guò)了。
(2)將這個(gè)二進(jìn)制格式實(shí)數(shù)的小數(shù)點(diǎn)左移或右移n位,直到小數(shù)點(diǎn)移動(dòng)到第一個(gè)有效數(shù)字的右邊。
(3)從小數(shù)點(diǎn)右邊第一位開始數(shù)出二十三位數(shù)字放入第22到第0位。
(4)如果實(shí)數(shù)是正的,則在第31位放入“0”,否則放入“1”。
(5)如果n 是左移得到的,說(shuō)明指數(shù)是正的,第30位放入“1”。如果n是右移得到的或n=0,則第30位放入“0”。
(6)如果n是左移得到的,則將n減去1后化為二進(jìn)制,并在左邊加“0”補(bǔ)足七位,放入第29到第23位。如果n是右移得到的或n=0,則將n化為二進(jìn)制后在左邊加“0”補(bǔ)足七位,再各位求反,再放入第29到第23位。

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

(1) 將11.9化為二進(jìn)制后大約是" 1011. 1110011001100110011001100..."。

(2) 將小數(shù)點(diǎn)左移三位到第一個(gè)有效位右側(cè): "1. 011 11100110011001100110 "。 保證有效位數(shù)24位,右側(cè)多余的截取(誤差在這里產(chǎn)生了 )。

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

(4) 因?yàn)?1.9是正數(shù),因此在第31位實(shí)數(shù)符號(hào)位放入“0”。

(5) 由于我們把小數(shù)點(diǎn)左移,因此在第30位指數(shù)符號(hào)位放入“1”。

(6) 因?yàn)槲覀兪前研?shù)點(diǎn)左移3位,因此將3減去1得2,化為二進(jìn)制,并補(bǔ)足7位得到0000010,放入第29到第23位。

最后表示11.9為: 0 1 0000010 011 11100110011001100110

再舉一個(gè)例子:0.2356的內(nèi)存存儲(chǔ)格式
(1)將0.2356化為二進(jìn)制后大約是0.00111100010100000100100000。
(2)將小數(shù)點(diǎn)右移三位得到1.11100010100000100100000。
(3)從小數(shù)點(diǎn)右邊數(shù)出二十三位有效數(shù)字,即11100010100000100100000放
入第22到第0位。
(4)由于0.2356是正的,所以在第31位放入“0”。
(5)由于我們把小數(shù)點(diǎn)右移了,所以在第30位放入“0”。
(6)因?yàn)樾?shù)點(diǎn)被右移了3位,所以將3化為二進(jìn)制,在左邊補(bǔ)“0”補(bǔ)足七
位,得到0000011,各位取反,得到1111100,放入第29到第23位。

最后表示0.2356為:0 0 1111100 11100010100000100100000

將一個(gè)內(nèi)存存儲(chǔ)的float二進(jìn)制格式轉(zhuǎn)化為十進(jìn)制的步驟:
(1)將第22位到第0位的二進(jìn)制數(shù)寫出來(lái),在最左邊補(bǔ)一位“1”,得到二十四位有效數(shù)字。將小數(shù)點(diǎn)點(diǎn)在最左邊那個(gè)“1”的右邊。
(2)取出第29到第23位所表示的值n。當(dāng)30位是“0”時(shí)將n各位求反。當(dāng)30位是“1”時(shí)將n增1。
(3)將小數(shù)點(diǎn)左移n位(當(dāng)30位是“0”時(shí))或右移n位(當(dāng)30位是“1”時(shí)),得到一個(gè)二進(jìn)制表示的實(shí)數(shù)。
(4)將這個(gè)二進(jìn)制實(shí)數(shù)化為十進(jìn)制,并根據(jù)第31位是“0”還是“1”加上正號(hào)或負(fù)號(hào)即可。

3、浮點(diǎn)型的減法運(yùn)算

浮點(diǎn)加減運(yùn)算過(guò)程比定點(diǎn)運(yùn)算過(guò)程復(fù)雜。完成浮點(diǎn)加減運(yùn)算的操作過(guò)程大體分為四步:
(1) 0操作數(shù)的檢查;

如果判斷兩個(gè)需要加減的浮點(diǎn)數(shù)有一個(gè)為0,即可得知運(yùn)算結(jié)果而沒(méi)有必要再進(jìn)行有序的一些列操作。

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

兩浮點(diǎn)數(shù)進(jìn)行加減,首先要看兩數(shù)的 指數(shù)位 是否相同,即小數(shù)點(diǎn)位置是否對(duì)齊。若兩數(shù) 指數(shù)位 相同,表示小數(shù)點(diǎn)是對(duì)齊的,就可以進(jìn)行尾數(shù)的加減運(yùn)算。反之,若兩數(shù)階碼不同,表示小數(shù)點(diǎn)位置沒(méi)有對(duì)齊,此時(shí)必須使兩數(shù)的階碼相同,這個(gè)過(guò)程叫做對(duì)階 。

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

通過(guò)尾數(shù)的移位以改變 Ex 或 Ey ,使之相等。 由 于浮點(diǎn)表示的數(shù)多是規(guī)格化的,尾數(shù)左移會(huì)引起最高有位的丟失,造成很大誤差;而尾數(shù)右移雖引起最低有效位的丟失,但造成的誤差較小,因此,對(duì)階操作規(guī)定使 尾數(shù)右移,尾數(shù)右移后使階碼作相應(yīng)增加,其數(shù)值保持不變。很顯然,一個(gè)增加后的階碼與另一個(gè)相等,所增加的階碼一定是小階。因此在對(duì)階時(shí),總是使小階向大階看齊 ,即小階的尾數(shù)向右移位 ( 相當(dāng)于小數(shù)點(diǎn)左移 ) ,每右移一位,其階碼加 1 ,直到兩數(shù)的階碼相等為止,右移的位數(shù)等于階差 △ E 。
(3) 尾數(shù)(有效數(shù)位)進(jìn)行加或減運(yùn)算;

對(duì)階完畢后就可 有效數(shù)位 求和。 不論是加法運(yùn)算還是減法運(yùn)算,都按加法進(jìn)行操作,其方法與定點(diǎn)加減運(yùn)算完全一樣。
(4) 結(jié)果規(guī)格化并進(jìn)行舍入處理。

4、 計(jì)算12.0f-11.9f

12.0f 的內(nèi)存存儲(chǔ)格式為: 0 1 0000010 10000000000000000000000

11.9f 的內(nèi)存存儲(chǔ)格式為: 0 1 0000010 011 11100110011001100110

可見(jiàn)兩數(shù)的指數(shù)位完全相同,只要對(duì)有效數(shù)位進(jìn)行減法即可。

12.0f-11.9f 結(jié)果: 0 1 0000010 00000011001100110011010

將結(jié)果還原為十進(jìn)制為: 0.000 11001100110011010= 0.10000038

總結(jié)

以上是生活随笔為你收集整理的float 精度_float相加产生精度损失的原因是什么?的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。