[十七]基礎類型BigDecimal簡介


 

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

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、1、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 的正負號函數
負、零或正時,返回 -1、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 時,返回 -1、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的名字起的不太規范,容易讓人迷惑,使用時要注意。
 
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM