溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Java中BigDecimal有什么用

發(fā)布時(shí)間:2021-09-09 10:32:05 來源:億速云 閱讀:185 作者:小新 欄目:編程語言

這篇文章主要介紹了Java中BigDecimal有什么用,具有一定借鑒價(jià)值,感興趣的朋友可以參考下,希望大家閱讀完這篇文章之后大有收獲,下面讓小編帶著大家一起了解一下。

為什么要有BigDecimal ,他是干什么的

float和double類型的主要設(shè)計(jì)目標(biāo)是為了科學(xué)計(jì)算和工程計(jì)算。他們執(zhí)行二進(jìn)制浮點(diǎn)運(yùn)算,這是為了在廣域數(shù)值范圍上提供較為精確的快速近似計(jì)算而精心設(shè)計(jì)的。然而,它們沒有提供完全精確的結(jié)果,所以不應(yīng)該被用于要求精確結(jié)果的場合。但是,商業(yè)計(jì)算往往要求結(jié)果精確,這時(shí)候就要使用BigDecimal啦。

什么是BigDecimal

BigDecimal 由任意精度的整數(shù)非標(biāo)度值 和32 位的整數(shù)標(biāo)度 (scale) 組成。如果為零或正數(shù),則標(biāo)度是小數(shù)點(diǎn)后的位數(shù)。如果為負(fù)數(shù),則將該數(shù)的非標(biāo)度值乘以 10 的負(fù)scale 次冪。因此,BigDecimal表示的數(shù)值是(unscaledValue × 10-scale)。

本文將給大家詳細(xì)介紹關(guān)于Java中BigDecimal精度和相等比較的坑,下面話不多說了,來一起看看詳細(xì)的介紹吧

先想一下,創(chuàng)建BigDecimal對(duì)象的時(shí)候一般是怎么創(chuàng)建的?

  • new一個(gè),傳進(jìn)去值

  • BigDecimal.valueOf方法,傳進(jìn)去值 

作為一個(gè)數(shù)字類型,經(jīng)常有的操作是比較大小,有一種情況是比較是否相等。用equal方法還是compareTo方法?這里就是一個(gè)大坑

//new 傳進(jìn)去一個(gè)double
BigDecimal newZero = new BigDecimal(0.0);
System.out.println(BigDecimal.ZERO.equals(newZero));
 
//new 傳進(jìn)去一個(gè)字符串
BigDecimal stringNewZero = new BigDecimal("0.0");
System.out.println(BigDecimal.ZERO.equals(stringNewZero));
 
//valueOf 傳進(jìn)去一個(gè)double
BigDecimal noScaleZero = BigDecimal.valueOf(0.0);
System.out.println(BigDecimal.ZERO.equals(noScaleZero));
 
//valueOf 傳進(jìn)去一個(gè)double,再手動(dòng)設(shè)置精度為1
BigDecimal scaleZero = BigDecimal.valueOf(0.0).setScale(1);
System.out.println(BigDecimal.ZERO.equals(scaleZero));

用于比較的值全都是0,猜一猜上面幾個(gè)equals方法返回的結(jié)果是什么?全都是true?no no no...

true
false
false
false

驚不驚喜,意不意外?原因是什么呢?看一下BigDecimal的equals方法的實(shí)現(xiàn):

public boolean equals(Object x) {
 //類型不同,直接返回false
 if (!(x instanceof BigDecimal))
  return false;
 BigDecimal xDec = (BigDecimal) x;
 //同一個(gè)對(duì)象,直接返回true
 if (x == this)
  return true;
 //精度不同,直接返回false!!
 if (scale != xDec.scale)
  return false;
 long s = this.intCompact;
 long xs = xDec.intCompact;
 if (s != INFLATED) {
  if (xs == INFLATED)
   xs = compactValFor(xDec.intVal);
  return xs == s;
 } else if (xs != INFLATED)
  return xs == compactValFor(this.intVal);
 
 return this.inflated().equals(xDec.inflated());
}

從前面三個(gè)簡單的判斷就可以看出來,debug跟一下就知道是上面equals方法有三個(gè)返回false,都是因?yàn)榫炔煌?。那?code>BigDecimal.ZERO的精度是多少呢?看下源碼:

// Cache of common small BigDecimal values.
private static final BigDecimal zeroThroughTen[] = {
 new BigDecimal(BigInteger.ZERO,  0, 0, 1),
 new BigDecimal(BigInteger.ONE,  1, 0, 1),
 new BigDecimal(BigInteger.valueOf(2), 2, 0, 1),
 new BigDecimal(BigInteger.valueOf(3), 3, 0, 1),
 new BigDecimal(BigInteger.valueOf(4), 4, 0, 1),
 new BigDecimal(BigInteger.valueOf(5), 5, 0, 1),
 new BigDecimal(BigInteger.valueOf(6), 6, 0, 1),
 new BigDecimal(BigInteger.valueOf(7), 7, 0, 1),
 new BigDecimal(BigInteger.valueOf(8), 8, 0, 1),
 new BigDecimal(BigInteger.valueOf(9), 9, 0, 1),
 new BigDecimal(BigInteger.TEN,  10, 0, 2),
};
 
 
/**
 * The value 0, with a scale of 0.
 *
 * @since 1.5
 */
public static final BigDecimal ZERO = zeroThroughTen[0];

BigDecimal.ZERO值為0,精度為0.

而上面幾種返回false的case,都是因?yàn)榫炔煌?。精度不同的原因,則是BigDecimal對(duì)象初始化的方式不同,從源碼上看,前三種初始化的方式都不同。

所以說,BigDecimal比較大小,還是用compareTo方法比較靠譜,改為compareTo之后,上面四個(gè)case返回的結(jié)果都是相等:

BigDecimal newZero = new BigDecimal(0.0);
System.out.println(BigDecimal.ZERO.compareTo(newZero));
 
BigDecimal stringNewZero = new BigDecimal("0.0");
System.out.println(BigDecimal.ZERO.compareTo(stringNewZero));
 
BigDecimal noScaleZero = BigDecimal.valueOf(0.0);
System.out.println(BigDecimal.ZERO.compareTo(noScaleZero));
 
BigDecimal scaleZero = BigDecimal.valueOf(0.0).setScale(1);
System.out.println(BigDecimal.ZERO.compareTo(scaleZero));

輸出結(jié)果

0
0
0
0

由此聯(lián)想到的一個(gè)更大的坑是,如果將BigDecimal的值作為HashMap的key,因?yàn)榫鹊膯栴},相同的值就可能出現(xiàn)hashCode值不同并且equals方法返回false,導(dǎo)致put和get就很可能會(huì)出現(xiàn)相同的值但是存取了不同的value。

再想一想,小數(shù)類型在計(jì)算機(jī)中本來就不能精確存儲(chǔ),再把其作為HashMap的key就相當(dāng)不靠譜了,以后還是少用。

另外需要注意的一點(diǎn)是,寫代碼調(diào)別人寫的方法時(shí),最好是點(diǎn)進(jìn)去看一下實(shí)現(xiàn)。再小再常用的方法,都可能埋著大坑

感謝你能夠認(rèn)真閱讀完這篇文章,希望小編分享的“Java中BigDecimal有什么用”這篇文章對(duì)大家有幫助,同時(shí)也希望大家多多支持億速云,關(guān)注億速云行業(yè)資訊頻道,更多相關(guān)知識(shí)等著你來學(xué)習(xí)!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請(qǐng)聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI