[十七]基礎類型BigDecimal簡介

 

BigDecimal是不可變的、任意精度的、有符號的、十進制數. git

image_5bdbee29_1474
 

組成部分

BigDecimal 由任意精度的整數非標度值 和 32 位的整數標度 (scale) 組成
BigDecimal 表示的數值是  :
unscaledValue × 10的-scale 次冪
私有成員intVal就是非標度值
scale就是標度

image_5bdbee29_6a7

 

標度

BigDecimal由非標度值 和 32 位的整數標度 (scale) 組成
BigDecimal表示的數爲: unscaledValue × 10的-scale 次冪
顯然
若是scale爲零或正數,最終的結果中,小數點後面的位數就等於scale標度
好比: scale爲1 10的-1次方,  0.1 小數點後有1位
若是 scale 是負數,那最終的結果將會是乘以 10的|scale| 次方
好比:  scale爲-3 最終的值就是非標度值乘以 1000  (    10的(- -3)次方   )
 

精度

非標度值的數字個數
 

構造方法

幾個關鍵概念  非標度值  標度 運算規則
構造方法就是圍繞這幾個點展開的
BigDecimal(BigInteger val) 將 BigInteger 轉換爲 BigDecimal
BigDecimal(BigInteger unscaledVal,int scale)
將 BigInteger 非標度值和 int 標度轉換爲 BigDecimal
BigDecimal(BigInteger unscaledVal,
                   int scale,
                   MathContext mc)
將 BigInteger 非標度值和 int 標度轉換爲 BigDecimal
(根據上下文設置進行舍入)
BigDecimal(BigInteger val,MathContext mc)
將 BigInteger 轉換爲 BigDecimal(根據上下文設置進行舍入)
 
BigDecimal(char[] in, int offset, int len, MathContext mc) 將 BigDecimal 的字符數組表示形式轉換爲 BigDecimal
容許指定子數組
根據上下文設置進行舍入
BigDecimal(char[] in, int offset, int len) 上一個方法的簡化默認形式
image_5bdbee29_24ba
BigDecimal(char[] in) 簡化形式
image_5bdbee29_7fe7
BigDecimal(char[] in, MathContext mc) 簡化形式
image_5bdbee29_53df
BigDecimal(String val)
調用的BigDecimal(char[] in, int offset, int len)
image_5bdbee29_566a
BigDecimal(String val, MathContext mc) 調用的是BigDecimal(char[] in, int offset, int len, MathContext mc)
image_5bdbee29_6a0
 
 
BigDecimal(int val) int 轉換爲 BigDecimal
BigDecimal(int val, MathContext mc) int 轉換爲 BigDecimal
根據上下文設置進行舍入
BigDecimal(long val) long 轉換爲 BigDecimal
BigDecimal(long val, MathContext mc) long 轉換爲 BigDecimal
根據上下文設置進行舍入
BigDecimal(double val) double 轉換爲 BigDecimal
BigDecimal(double val, MathContext mc) double 轉換爲 BigDecimal
根據上下文設置進行舍入
 

構造方法注意事項

BigDecimal(double val)
BigDecimal(double val, MathContext mc)
這兩個構造方法具備必定的不肯定性
以下圖所示,這是由於在二進制中沒法準確地表示0.1 如同十進制沒法準確表示 1/3 同樣
image_5bdbee29_74ea
 
當 double 必須用做 BigDecimal 的源時
請注意,此構造方法public BigDecimal(double val)提供了一個準確轉換;
不等同於下面的操做:
先使用 Double.toString(double) 方法,
而後使用 BigDecimal(String) 構造方法
要獲取該結果,請使用 static valueOf(double) 方法
 

String構造方法的格式

Sign(可選) Significand Exponent opt(可選)
Sign 符號:
+
-
 
Significand 有效數字至少要有整數或者小數的一位數字:
IntegerPart .FractionPart  整數和小數
. FractionPart   小數
IntegerPart      整數
 
IntegerPart:
Digits
 
FractionPart:
Digits
 
Exponent:  指數部分
ExponentIndicator SignedInteger
 
ExponentIndicator: 指數符號
e
E
 
SignedInteger: 有符號數
Sign(可選的) Digits
 
Digits:
Digit
Digits Digit
 
Digit:
Character.isDigit(char) 對其返回 true 的任何字符,如 0、一、2……
 
-1.23E-12
這是一個完整的格式
含有符號  / 含有整數部分 / 含有小數部分 /含有指數部分/指數部分含有符號
 
除非有必要
不然在你須要 將 float 或 double 轉換爲 BigDecimal時
首選BigDecimal(String val)
構造方法與 Float.toString(float) 和 Double.toString(double) 返回的值兼容
它不會遇到 BigDecimal(double) 構造方法的不可預知問題
 

常量

內部定義了幾個public final static int的常量,用於標註舍入模式
與RoundingMode中是一一對應的,這幾個不要再使用了
請使用RoundingMode中的枚舉值
ROUND_UP
ROUND_DOWN
 
ROUND_CEILING
ROUND_FLOOR
 
ROUND_HALF_UP
ROUND_HALF_DOWN
ROUND_HALF_EVEN
 
ROUND_UNNECESSARY
 
另外還有三個經常使用對象
public static final BigDecimal ZERO
public static final BigDecimal ONE
public static final BigDecimal TEN
 

經常使用方法

屬性獲取

int signum() 返回此 BigDecimal 的正負號函數
負、零或正時,返回 -一、0 或 1
int scale() 返回此 BigDecimal 的標度
int precision()
返回此 BigDecimal 的精度。(精度是非標度值的數字個數。)
零值的精度是 1
BigInteger unscaledValue() 返回其值爲此 BigDecimal 的非標度值 的 BigInteger
image_5bdbee29_79fb
 

四則運算

除非結果準確,每種運算都有一個表示結果的首選標度
這些標度是返回準確算術結果的方法使用的標度
image_5bdbee29_54ed
 
add(BigDecimal augend)
計算 this + augend
標度爲:
max(this.scale(), augend.scale())
add(BigDecimal augend, MathContext mc)
計算 this + augend
根據上下文設置進行舍入
subtract(BigDecimal subtrahend)
計算 this - subtrahend
標度爲 :
max(this.scale(), subtrahend.scale())
subtract(BigDecimal subtrahend, MathContext mc)
計算 this - subtrahend
根據上下文設置進行舍入
multiply(BigDecimal multiplicand)
計算 this × multiplicand
標度爲 :
(this.scale() + multiplicand.scale())
multiply(BigDecimal multiplicand, MathContext mc)
計算 this × multiplicand)
根據上下文設置進行舍入
divide(BigDecimal divisor, int scale, int roundingMode)
計算 this / divisor
指定標度
若是須要舍入則會使用指定的模式進行舍入
 
應該使用
divide(BigDecimal, int, RoundingMode)
進行替代
divide(BigDecimal divisor,
          int scale,
          RoundingMode roundingMode)
image_5bdbee29_37d5
做爲上面divide方法的替代
目前仍舊映射到原來的遺留方法上
將RoundingMode轉換爲了int
相對於上一個方法,應該優先使用這個方法
divide(BigDecimal divisor, int roundingMode) 簡化轉換形式
image_5bdbee29_45c4
divide(BigDecimal divisor, RoundingMode roundingMode) 簡化轉換形式
image_5bdbee29_768a
divide(BigDecimal divisor) 計算 this / divisor
首選標度爲 (this.scale() - divisor.scale());
若是沒法表示準確的商值(由於它有無窮的十進制擴展)
則拋出 ArithmeticException
divide(BigDecimal divisor, MathContext mc) 計算 this / divisor
根據上下文設置進行舍入
 
divideToIntegralValue(BigDecimal divisor) 返回 BigDecimal
值爲向下舍入所得商值 (this / divisor) 的整數部分
首選標度爲 (this.scale() - divisor.scale())
divideToIntegralValue(BigDecimal divisor, MathContext mc) 返回 BigDecimal
其值爲 (this / divisor) 的整數部分
準確商值的整數部分與舍入模式無關
因此舍入模式不影響此方法返回的值
首選標度是 (this.scale() - divisor.scale())

若是準確商值的整數部分須要的位數多於 mc.precision
則拋出 ArithmeticException
 
divideToIntegralValue 須要注意由於是取整數部分,因此舍入模式是不影響的
針對於參數MathContext 有影響的是精度
 
BigDecimal[] divideAndRemainder(BigDecimal divisor)  計算商和餘數
返回由兩個元素組成的 BigDecimal 數組
該數組包含 divideToIntegralValue 的結果
後跟對兩個操做數計算所獲得的 remainder

BigDecimal[] divideAndRemainder(BigDecimal divisor, MathContext mc)
計算商和餘數
返回由兩個元素組成的 BigDecimal 數組
該數組包含 divideToIntegralValue 的結果
後跟
根據上下文設置對兩個操做數進行舍入計算所獲得的 remainder
 
remainder(BigDecimal divisor) image_5bdbee29_755
remainder(BigDecimal divisor, MathContext mc) image_5bdbee29_810
 

注意

若是同時須要整數商和餘數
則divideAndRemainder比分別使用 divideToIntegralValue 和 remainder 方法更快速,由於相除僅需執行一次
remainder則是依賴於divideAndRemainder ,而後返回的第二個元素
 

數學方法

BigDecimal pow(int n)
求n次冪
準確計算該冪,使其具備無限精度
參數 n 必須在 0 到 999999999(包括)之間
ZERO.pow(0) 返回 ONE
-若是 n 超出範圍 拋出異常ArithmeticException
pow(int, MathContext)
求n次冪
使用的是 ANSI 標準 X3.274-1996 中定義的核心算法(根據上下文設置進行舍入)
BigDecimal abs()
求絕對值
其標度爲 this.scale() 
BigDecimal abs(MathContext mc)
求絕對值
根據上下文設置進行舍入
最大值max
最小值min

藉助於compareTo
image_5bdbee29_573c
int compareTo(BigDecimal val)
值相等但具備不一樣標度的兩個 BigDecimal 對象(如,2.0 和 2.00)被認爲是相等的
注意:與equals中的相等含義不一樣
小於、等於或大於 val 時,返回 -一、0 或 1
 

equals

判斷是否相等
與 compareTo 不一樣
僅當兩個 BigDecimal 對象的值和標度都相等時,此方法才認爲它們相等
(所以經過此方法進行比較時,2.0 不等於 2.00)
必定要注意到compareTo方法與equals方法 對於相等的定義是不一致的
 

valueOf

public static BigDecimal valueOf(long val)
將 long 值轉換爲具備零標度的 BigDecimal
這個方法優先於以long爲參數的構造方法

以下圖所示,這個valueOf方法會進行緩存
image_5bdbee29_758c
public static BigDecimal valueOf(long unscaledVal, int scale)
將 long 非標度值和 int 標度轉換爲 BigDecimal
看得出來這個valueOf版本也是會藉助於緩存的
因此優先於構造方法
image_5bdbee2a_3754
valueOf(double val)
使用 Double.toString(double) 方法轉換 double 爲字符串
而且 調用構造方法

此方法並沒有涉及到緩存
回頭看下上面說的String參數類型的構造方法
String參數類型的構造方法---與 Float.toString(float) 和 Double.toString(double) 返回的值兼容
這個valueOf藉助的就是toString方法
這個版本valueOf是float和double轉換爲BigDecimal的首選
image_5bdbee2a_1b40
 

setScale

setScale 系列並非設置BigDecimal的scale  BigDecimal是不可變得
setScale 是一個轉換器,將參數的BigDecimal轉換爲指定標度的值
值自己不會變化,變化的是形式
返回的是一個新的BigDecimal,不過這個新的BigDecimal並不必定是新建立的
多是使用緩存,新是相對於調用者來講
image_5bdbee2a_355f
 
方法列表:
public BigDecimal setScale(int newScale, int roundingMode)
返回一個 BigDecimal
其標度爲指定值
其非標度值經過此 BigDecimal 的非標度值乘以或除以十的適當次冪來肯定,以維護其總值
相對於此遺留方法,應優先使用新的 setScale(int, RoundingMode) 方法
public BigDecimal setScale(int newScale, RoundingMode roundingMode)
setScale(int newScale, int roundingMode) 的替代形式
使用RoundingMode枚舉
image_5bdbee2a_52d6
BigDecimal setScale(int newScale)
返回一個 BigDecimal
其標度爲指定值,其值在數值上等於此 BigDecimal 的值
若是這不可能,則拋出 ArithmeticException

省略了模式,其實就是默認了模式,默認爲 UNNECESSARY
UNNECESSARY 用於斷言,因此若是結果須要舍入的話,,則會拋出異常
image_5bdbee2a_63b5
 

negate/plus/round

BigDecimal negate()
取負數
返回 BigDecimal,值爲 (-this),標度爲 this.scale() 
BigDecimal negate(MathContext mc)
根據指定上下文設置取負數
返回其值爲 (-this) 的 BigDecimal(根據上下文設置進行舍入)。
image_5bdbee2a_7058
BigDecimal plus()
返回自己  任何一個數前面加正號 都是它自己
值爲 (+this),標度爲 this.scale()
image_5bdbee2a_729b
BigDecimal plus(MathContext mc)
返回其值爲 (+this) 的 BigDecimal
(根據上下文設置進行舍入)
方法的效果與 round(MathContext) 方法的效果相同
BigDecimal round(MathContext mc)
等同於BigDecimal plus(MathContext mc)
image_5bdbee2a_17a
 

xxxValue

intValue()
轉換爲 int
丟棄此 BigDecimal 的小數部分
若是生成的 "BigInteger" 太大而不適合用 int 表示,則僅返回 32 位低位字節
此轉換會丟失關於此 BigDecimal 值的總大小和精度的信息
longValue()
轉換爲 long
丟棄此 BigDecimal 的小數部分
若是生成的 "BigInteger" 太大
僅返回 64 位低位字節
此轉換會丟失關於此 BigDecimal 值的總大小和精度的信息
floatValue()
轉換爲 float
若是BigDecimal 的值太大而不能表示爲 float
將其適當地轉換爲 Float.NEGATIVE_INFINITY 或 Float.POSITIVE_INFINITY
此轉換也可能丟失關於 BigDecimal 值精度的信息
doubleValue()
轉換爲 double
若是此 BigDecimal 的數量太大而不能表示爲 double
將其適當地轉換爲 Double.NEGATIVE_INFINITY 或 Double.POSITIVE_INFINITY
轉換也可能丟失關於 BigDecimal 值精度的信息
BigInteger toBigInteger()
轉換爲 BigInteger
丟棄此 BigDecimal 的小數部分
此轉換會丟失關於 BigDecimal 值的精度信息
 

XXXValueExact

byte byteValueExact()
轉換爲 byte
若是此 BigDecimal 具備非零小數部分,或者超出 byte 結果的可能範圍
拋出 ArithmeticException
image_5bdbee2a_295a
short shortValueExact()
轉換爲 short
若是此 BigDecimal 具備非零小數部分,或者超出 short 結果的可能範圍
拋出 ArithmeticException
image_5bdbee2a_33f5
int intValueExact()
轉換爲 int
若是此 BigDecimal 具備非零小數部分,或者超出 int 結果的可能範圍
拋出 ArithmeticException
image_5bdbee2a_4e60
long longValueExact()
轉換爲 long
若是此 BigDecimal 具備非零小數部分,或者超出 long 結果的可能範圍
拋出 ArithmeticException
BigInteger toBigIntegerExact()
轉換爲 BigInteger
若是此 BigDecimal 具備非零小數部分,則拋出一個異常
 
exact版本的區別就在因而否可以準確轉換,不然拋出異常
也就是他要麼返回一個準確地值要麼就拋出異常
 

hashCode

int hashCode()
返回此 BigDecimal 的哈希碼
數值上相等但標度不一樣的兩個 BigDecimal 對象(如,2.0 和 2.00)一般沒有 相同的哈希碼
 

toString

toString() 返回字符串表示形式,若是須要指數,則使用科學記數法
toEngineeringString() 返回字符串表示形式,須要指數時,則使用工程計數法
toPlainString()  返回不帶指數字段的此 BigDecimal 的字符串表示形式
toString的三個方法根本邏輯是同樣的,都是轉換爲字符串
只不過具體的形式不一樣
 

ulp

unit in the last place
兩個數之間的距離,在數學中是無限的,好比1和2之間有無數個數
可是在計算機中是有限的,由於計算機須要用有限個字節來表示double或者float,計算機表示不了無限的數
由於沒有無限內存
假設兩個數之間有10個數,那麼ulp 就是1/10 
1和2之間有一個數 距離爲1
1.1和2.1之間有十個數  距離爲0.1
這就是ulp
 
非零 BigDecimal 值的 ulp 是此值與下一個具備相同位數的較大 BigDecimal 值之間的正距離
零值的 ulp 在數值上等於1 和 this.scale()之間的距離
因此能夠說全部的數的ulp爲[1, this.scale()]
image_5bdbee2a_4d96
 

移動小數點

movePointLeft
該值的小數點向左移動 n 位
若是 n 爲負數,則該調用等效於 movePointRight(-n)
若是 n 爲非負數,則調用僅將 n 添加到該標度
返回的標度分別爲:
image_5bdbee2a_2cfe
image_5bdbee2a_5e59
movePointRight
小數點向右移動 n 位
若是 n 爲負,則該調用等效於 movePointLeft(-n)
若是 n 爲非負數,則該調用僅從該標度減去 n
返回的標度分別爲:
image_5bdbee2a_6782
image_5bdbee2a_1089
 
BigDecimal scaleByPowerOfTen(int n)
返回其數值等於
image_5bdbee2a_3358
的BigDecimal

該結果的標度爲:
image_5bdbee2a_6ef1
BigDecimal stripTrailingZeros()
形式轉換,數值是相等的
轉換爲去掉全部尾部的0的形式的數值
800.000去掉全部的0 就是8   準換後爲8乘以10的平方
 
 

總結

BigDecimal雖然有諸多特性與特別,,可是本質仍舊是浮點數
因此天然提供了浮點數相關的一些操做
做爲數值的基本運算方法都具有的
須要注意的是構造方法之間的區別
除非特別須要,不然不要直接使用double構造
儘量的使用String的形式
對於valueOf方法也是具備緩存的
BigDecimal是不可變的
setScale的名字起的不太規範,容易讓人迷惑,使用時要注意。
相關文章
相關標籤/搜索