您好,登錄后才能下訂單哦!
這篇文章主要介紹“Java中浮點數(shù)有哪些需要注意的問題”,在日常操作中,相信很多人在Java中浮點數(shù)有哪些需要注意的問題問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”Java中浮點數(shù)有哪些需要注意的問題”的疑惑有所幫助!接下來,請跟著小編一起來學(xué)習(xí)吧!
浮點數(shù)有一個需要特別注意的點就是浮點數(shù)是有誤差的,比如以下這段代碼你覺得輸出的什么結(jié)果:
public class Demo { public static void main(String[] args) { System.out.println(0.1+0.2 == 0.3);//輸出false } }
這段代碼輸出值是false,之所以是這個結(jié)果那是因為浮點數(shù)是存在誤差的,也就yi是說0.1在計算機(jī)中存儲時不是精確的0.1,而有可能是0.1000000001,或者其他數(shù),而0.2或0.3也是如此,所以0.1+0.2和0.3在計算機(jī)中是不相等的。
因為浮點數(shù)存在這個特性,所以我們在編程中間要盡量避免用浮點數(shù)進(jìn)行比較。
如果非要用浮點數(shù)進(jìn)行比較的話,那可以使用下面這個方法:
public class Demo { public static void main(String[] args) { float n = (float)1e-6;//表示10的-6次方 System.out.println(0.1+0.2 - 0.3 < n);//輸出true } }
以上代碼的輸出值是true,該方法的原理是如果兩個數(shù)相差足夠小,小到可以忽略不記的話,這里的界限設(shè)置是10的-6次方,那證明比較的這兩個數(shù)可以認(rèn)為是相等的,此方法只能在所表示的浮點數(shù)的小數(shù)點后的位數(shù)不是很多的時候使用。
接下來我們再來看一種極端的情況,代碼如下:
public class Demo { public static void main(String[] args) { System.out.println(0.30000000000000001 == 0.3);//輸出true } }
以上的代碼輸出true,但其實我們?nèi)庋劭梢院苤庇^的看出,這兩個數(shù)雖然很接近,但他們絕對不相等,像這種極端的數(shù)我們是無法用上面的方法進(jìn)行比較的,所以還是記住這句話:盡量避免對浮點數(shù)進(jìn)行比較。
我們既然知道了浮點數(shù)是存在誤差的,所以在數(shù)據(jù)本身需要準(zhǔn)確精度存儲時,我們是一定不會使用float和double的,比如金錢數(shù)額的存儲。這時我們通常使用BigDecimal
類進(jìn)行存儲,它是一個可以存儲準(zhǔn)確浮點數(shù)的類。
BigDecimal
類的定義:
BigDecimal bd = new BigDecimal("123.456");
BigDecimal
使用scale()
表示小數(shù)位數(shù),例如:
BigDecimal d1 = new BigDecimal("987.65"); BigDecimal d2 = new BigDecimal("987.6500"); BigDecimal d3 = new BigDecimal("98765400"); System.out.println(d1.scale()); // 2,表示兩位小數(shù) System.out.println(d2.scale()); // 4 System.out.println(d3.scale()); // 0
BigDecimal
中的stripTrailingZeros()
方法,可以將BigDecimal
格式化為去掉數(shù)值末尾0的相等的數(shù):
BigDecimal d1 = new BigDecimal("123.4500"); BigDecimal d2 = d1.stripTrailingZeros(); System.out.println(d1+" "+d1.scale()); // 123.4500 4 System.out.println(d2+" "+d2.scale()); // 123.45 2,因為去掉了00 BigDecimal d3 = new BigDecimal("1234500"); BigDecimal d4 = d3.stripTrailingZeros(); System.out.println(d3+" "+d3.scale()); // 1234500 0 System.out.println(d4+" "+d4.scale()); // 1.2345E+6 -2
BigDecimal
的scale()
返回負(fù)數(shù),例如,-2
,表示這個數(shù)是個整數(shù),并且末尾有2個0。以上的d4就是如此,去掉0后數(shù)值沒變,只是換了一種表示方法。
BigDecimal
可以設(shè)置它的scale
,如果精度比原始值低,那么按照指定的方法進(jìn)行四舍五入或者直接截斷:
import java.math.BigDecimal; import java.math.RoundingMode; public class Demo { public static void main(String[] args) { BigDecimal d1 = new BigDecimal("123.456789"); BigDecimal d2 = d1.setScale(4, RoundingMode.HALF_UP); // 四舍五入,123.4568 BigDecimal d3 = d1.setScale(4, RoundingMode.DOWN); // 直接截斷,123.4567 System.out.println(d2);//123.4568 System.out.println(d3);//123.4567 } }
BigDecimal
的加、減、乘、除:
import java.math.BigDecimal; public class Demo { public static void main(String[] args) { BigDecimal d1 = new BigDecimal("124.44"); BigDecimal d2 = new BigDecimal("12.2"); System.out.println(d1.add(d2));//d1+d2 136.64 System.out.println(d1.subtract(d2));//d1-d2 112.24 System.out.println(d1.multiply(d2));//d1*d2 1518.168 System.out.println(d1.divide(d2));//d1/d2 10.2 } }
BigDecimal
在做加、減、乘時,精度不會丟失,但是做除法時,存在無法除盡的情況,這時就必須指定精度以及如何進(jìn)行截斷:
import java.math.BigDecimal; import java.math.RoundingMode; public class Demo { public static void main(String[] args) { BigDecimal d1 = new BigDecimal("123.456"); BigDecimal d2 = new BigDecimal("23.456789"); BigDecimal d3 = d1.divide(d2, 10, RoundingMode.HALF_UP); // 保留10位小數(shù)并四舍五入 BigDecimal d4 = d1.divide(d2); // 報錯:ArithmeticException,因為除不盡 } }
可以對BigDecimal
做除法的同時求其余數(shù):
import java.math.BigDecimal; public class Demo { public static void main(String[] args) { BigDecimal n = new BigDecimal("22.444"); BigDecimal m = new BigDecimal("0.23"); BigDecimal[] dr = n.divideAndRemainder(m); System.out.println(dr[0]); // 97.0 System.out.println(dr[1]); // 0.134 } }
調(diào)用divideAndRemainder()
方法時,返回的數(shù)組包含兩個BigDecimal
,第一個是商,第二個是余數(shù),商總是整數(shù),余數(shù)不會大于余數(shù),我們可以利用該方法判斷兩個BigDecimal
是否是整數(shù)倍數(shù):
BigDecimal n = new BigDecimal("12.34"); BigDecimal m = new BigDecimal("0.12"); BigDecimal[] dr = n.divideAndRemainder(m); if (dr[1].signum() == 0) {//signum()會基于此BigDecimal返回三個值-1、1、0,分別對應(yīng)為該數(shù)小于0,大于0和等于0 // n是m的整數(shù)倍 }
比較兩個BigDecimal
的值是否相等時,要注意的是,使用equals()
方法不但要求兩個BigDecimal
的值相等,還要求它們的scale()
相等:
BigDecimal d1 = new BigDecimal("123.45"); BigDecimal d2 = new BigDecimal("123.45000"); System.out.println(d1.equals(d2)); // false,因為scale不同 System.out.println(d1.equals(d2.stripTrailingZeros())); // true,因為d2去除尾部0后scale變?yōu)?,與d1相同
注意:使用compareTo()
來比較兩個BigDecimal
的值,不要用equals()
使用compareTo()
方法來比較兩數(shù)大小,它根據(jù)兩個值的大小分別返回-1、1和0
,分別表示小于、大于和等于。
import java.math.BigDecimal; public class Demo { public static void main(String[] args) { BigDecimal d1 = new BigDecimal("123.45"); BigDecimal d2 = new BigDecimal("123.45000"); BigDecimal d3 = new BigDecimal("123.40"); System.out.println(d1.compareTo(d2)); // 0 System.out.println(d1.compareTo(d3));// 1 System.out.println(d3.compareTo(d2));// -1 } }
查看BigDecimal
的源碼,可以發(fā)現(xiàn)一個BigDecimal
是通過一個BigInteger
和一個scale
來表示的,即BigInteger
表示一個完整的整數(shù),而scale
表示小數(shù)位數(shù):
public class BigDecimal extends Number implements Comparable<BigDecimal> { private final BigInteger intVal; private final int scale; }
到此,關(guān)于“Java中浮點數(shù)有哪些需要注意的問題”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識,請繼續(xù)關(guān)注億速云網(wǎng)站,小編會繼續(xù)努力為大家?guī)砀鄬嵱玫奈恼拢?/p>
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。