天天看點

Java 常用類庫之 BigDecimal

完整名<code>java.math.BigDecimal</code>

提供不可變的,任意精度的帶符号十進制數。一個<code>BigDecimal</code>有一個任意精度的整型非縮放值<code>unscaledValue</code>和一個 32 位整型縮放值<code>scale</code>組成。<code>scale</code>就是用于指定<code>unscaledValue</code>的縮放量級,<code>scale &gt;= 0</code>時,它表示小數點右邊的位數,<code>scale &lt; 0</code>時,它表示目前<code>BigDecimal</code>對象對應的數值為<code>unscaledValue*10^(-scale)</code>。

<code>BigDecimal</code>類提供了算術,縮放操作,舍入,比較,散列和格式轉換的操作。 <code>toString()</code>方法提供了一個<code>BigDecimal</code>的規範表示 。 由于<code>BigDecimal</code>對象是可變的,是以每次算數操作都傳回一個新的<code>BigDecimal</code>對象表示運算結果。

<code>BigDecimal</code>提供了表示數字 0、1 和 10 的三個整數常量。

這裡的<code>ZERO_THROUGH_TEN</code>數組儲存了整數 0-10 對應的所有 <code>BigDecimal</code>對象。

<code>BigDecimal</code>原本提供了針對舍入操作的一系列常量,如<code>ROUND_HALF_EVEN</code>等,但在 Java 9 之後被棄用,使用 <code>RoundingMode.HALF_EVEN</code>等枚舉值表示同樣的作用。

構造方法<code>BigDecimal()</code>

<code>BigDecimal</code>的構造方法根據接收的資料種類可以分為三類:字元類型的、數字類型和<code>BigInteger</code>類型。

接收字元類型的構造器包括接收字元數組<code>char[]</code>和字元串<code>String</code>。

從源碼中可以看出,真正起作用的構造器就是構造器 [1],其它幾個構造器都是通過直接或者間接地調用它來實作的。是以這裡隻需要明白構造器 [1] 的參數意義就可以了。參數<code>in</code>必須是一個可以表示某個數字的字元數組(可以包含e,表示科學計數,但也需要在有意義的位置),否則程式會産生異常<code>NumberFormatException</code>;<code>offset</code>和<code>len</code>指定觀察的範圍,<code>offset</code>表示從<code>in</code>中觀察的第一個位置,<code>len</code>表示需要觀察的長度即字元個數;<code>mc</code>是一個<code>MathContext</code>對象,用于指定以怎樣的精度以及舍入方式生成<code>BigDecimal</code>表示的值。舉一個例子:

這裡表示以<code>num</code>數組的 <code>'3'</code>到<code>'5'</code>部分生成<code>BigDecimal</code>對象,<code>MathContext</code>對象指定的精度為 4(表示保留 4 個有效數字),使用<code>RoundingMode.HALF_EVEN</code>的舍入方式。

接收數字類型的構造器包括接收<code>double/int/long</code>三種基本資料類型。

接收<code>BigInteger</code>對象的構造器

<code>BigInteger</code>是一個與<code>BigDecimal</code>類似的不可變的表示整數的對象。構造器中的參數<code>scale</code>指定量級為 -scale。在看一個例子就知道了:

<code>valueOf()</code>

該方法提供了一個直接從資料類型生成<code>BigDecimal</code>對象的方式,使用方式是直接傳入需要轉換的基本資料類型,支援<code>long/double</code>兩種基本資料類型。

<code>add()</code>

使用<code>add()</code>對目前<code>BigDecimal</code>對象<code>this</code>跟另一個<code>BigDecimal</code>對象參數<code>augend</code>作加法操作,對應于數值上的<code>this + augend</code>,傳回結果為一個新的<code>BigDecimal</code>對象。

<code>subtract()</code>

使用<code>subtract()</code>對目前<code>BigDecimal</code>對象<code>this</code>跟另一個<code>BigDecimal</code>對象參數<code>subtrahend</code>作減法操作,對應于數值上的<code>this - subtrahend</code>,傳回結果為一個新的<code>BigDecimal</code>對象。

<code>multiply()</code>

使用<code>multiply()</code>對目前<code>BigDecimal</code>對象<code>this</code>跟另一個<code>BigDecimal</code>對象參數<code>multiplicand</code>作減法操作,對應于數值上的<code>this * subtrahend</code>,傳回結果為一個新的<code>BigDecimal</code>對象。

<code>divide()</code>

使用<code>divide()</code>對目前<code>BigDecimal</code>對象<code>this</code>跟另一個<code>BigDecimal</code>對象參數<code>divisor</code>作減法操作,對應于數值上的<code>this / divisor</code>,傳回結果為一個新的<code>BigDecimal</code>對象。

<code>divideToIntegralValue()</code>

同樣作除法操作,但傳回所得商值的整數部分。

<code>remainder()</code>

使用<code>remainder()</code>對目前<code>BigDecimal</code>對象<code>this</code>跟另一個<code>BigDecimal</code>對象參數<code>divisor</code>作取餘操作,對應于數值上的<code>this % divisor</code>,傳回結果為一個新的<code>BigDecimal</code>對象。

<code>divideAndRemainder()</code>

相當于同時進行了<code>divideToIntegralValue()</code>和<code>remainder()</code>兩個操作,傳回一個<code>BigDecimal</code>數組,包含兩個元素,第一個是<code>divideToIntegralValue()</code>的結果,第二個是<code>remainder()</code>的結果。

注意,如果有同時得到整數商和餘數的需求,使用該方法比分别使用<code>divideToIntegralValue()</code>和<code>remainder()</code>兩個方法要快,因為它的内部隻做了一次除法。

<code>pow()</code>

求幂操作,求<code>this</code>對應值的 n 次方,傳回結果為一個新的<code>BigDecimal</code>對象。

<code>abs()</code>

求絕對值,即求<code>|this|</code>。

<code>negate()</code>

反轉操作,即求<code>-this</code>。

<code>plus()</code>

傳回目前<code>BigDecimal</code>的對象值,即<code>+this</code>。它的存在是為了和<code>negate()</code>方法保持對稱性。

<code>signum()</code>

傳回目前<code>BigDecimal</code>表示數值的符号。傳回 -1 代表負數,0 代表零,1 代表正數。

<code>scale()</code>

傳回目前<code>BigDecimal</code>對象的<code>scale</code>值。<code>scale</code>值的作用已經在開頭說明。

<code>percision()</code>

傳回目前<code>BigDecimal</code>的精度,即有效位數。

<code>unscaledValue()</code>

傳回一個<code>BigInteger</code>對象(假設為<code>unscaledValue</code>),其對應的值為目前<code>BigDecimal</code>的非縮放值,即是<code>this * 10^(this.scale())</code>。

<code>round()</code>

根據參數<code>mc</code>指定的精度傳回一個近似值的<code>BigDecimal</code>對象。

<code>setScale()</code>

設定縮放量級。<code>setScale()</code>主要用于對<code>BigDecimal</code>資料小數點後的位數進行進位、舍位、截斷等操作。

<code>movePointLeft()</code>和<code>movePointRight()</code>

前者左移小數點,後者右移小數點,傳回移動小數點後的一個新<code>BigDecimal</code>對象。

<code>scaleByPowerOfTen()</code>

在原數上乘以 10 的 n 次方,傳回新的<code>BigDecimal</code>對象。

<code>stripTrailingZeros()</code>

傳回一個<code>BigDecimal</code>對象,其對應的數值等于原對象數值,但移除了尾部零。比如對于值為 600.0 的<code>BigDecimal</code>,其 [<code>BigInteger</code>, <code>scale</code>] 組成為 [6000, 1],那麼通過該方法得到的<code>BigDecimal</code>其值為 6e2,對應的 [<code>BigInteger</code>, <code>scale</code>] 組成為 [6, -2]。如果該<code>BigDecimal</code>在數值上等于零,則方法傳回<code>BigDecimal.ZERO</code> 。

<code>compareTo()</code>

比較目前<code>BigDecimal</code>值和<code>val</code>對象值,傳回 -1、0 或 1,分别代表目前<code>BigDecimal</code>值小于、等于或小于<code>val</code>值。對于兩個值相同而 scale 值不同的<code>BigDecimal</code>對象,比如其值為 2.0 和 2.00,該方法判定為兩者相等。

<code>equals()</code>

判斷目前<code>BigDecimal</code>對象于所給參數對象<code>x</code>是否相等。與<code>compareTo()</code>不同,<code>equals()</code>要求隻有兩個<code>BigDecimal</code>的 value 值和 scale 值都相等時,才判定兩者相等(是以 2.0 和 2.00 是不相等的)。

<code>min()</code>和<code>max()</code>

前者傳回目前<code>BigDecimal</code>對象和<code>val</code>之間的最小值,後者傳回兩者之間的最大值。

<code>hashCode()</code>

傳回目前對象的哈希碼(2.0 和 2.00 的哈希碼是不同的)。

<code>toString()</code>、<code>toEngineeringString()</code>和<code>toPlainString()</code>

<code>toString()</code>以字元串形式傳回目前<code>BigDecimal</code>對象表示的數值,必要時會使用科學計數法。

<code>toEngineeringString()</code>基本上和<code>toString()</code>傳回同樣的結果。不同的地方在于當傳回的結果為科學計數法的形式時。

<code>toPlainString()</code>不會傳回科學計數法的形式。看一個例子吧:

<code>toEngineeringString()</code>在輸出為科學計數法時,會讓 10 的指數為 3 的倍數,這樣表示出的整數部分就處于 1 到 999 之間。

<code>toBigInteger()</code>和<code>toBigIntegerExact()</code>

兩者都是将目前的<code>BigDecimal</code>轉換得到一個<code>BigInteger</code>對象。前者在轉換中會丢掉原數的小鼠部分,是以可能有資訊損失;後者不允許資訊損失,是以當原數存在非零小數部分時,會直接抛出異常<code>ArithmeticException</code>。

<code>lnogValue()</code>和<code>longValueExact()</code>

兩者都時将目前<code>BigDecimal</code>轉換得到一個<code>long</code>型整數。前者類似于基本收縮轉換(arrowing primitive conversion),即去掉小數部分,并且當整數部分的<code>BIgInteger</code>值超出<code>long</code>型資料範圍時,取其低 64 位,是以可能有資訊損失;後者不允許資訊損失,是以當遇到非零小數部分或者整數部分超限時,直接抛出異常<code>ArithmeticException</code>。

<code>shorValueExact()</code>和<code>byteValueExact()</code>

作用和<code>longValueExact()</code>類似,隻是分别轉換得到<code>short</code>型和1<code>byte</code>型資料。都不允許資訊丢失。

<code>floatValue()</code>和<code>doubleValue()</code>

轉換目前<code>BigDecimal</code>對象值得到浮點型資料,轉換允許資訊損失。

<code>ulp()</code>

傳回目前<code>BigDecimal</code>的最後位置機關大小(ulp)。實際上它的值為 [<code>1</code>, <code>this.scale()</code>],即 <code>1*10^(-this.scale())</code>。

以下是從 Java 9 開始加入的方法:

<code>sqrt()</code>

開平方操作,傳回結果為一個新的<code>BigDecimal</code>對象。