Bigdecimal 數據轉換精度缺失
使用 new BigDecimal()、.valueof() 和 new BigDecimal("[字符串]")的區別
構造 BigDecimal 對象常用以下方法:
BigDecimal BigDecimal(double d); //不允許使用
BigDecimal BigDecimal(String s); //常用,推薦使用
static BigDecimal valueOf(double d); //常用,推薦使用
其原因有
- double 參數的構造方法,不允許使用!!!!因為它不能精確的得到相應的值;
- String 構造方法是完全可預知的: 寫入 new BigDecimal("0.1") 將創建一個 BigDecimal,它正好等於預期的0.1; 因此,通常建議優先使用 String 構造方法;
- 靜態方法 valueOf(double val) 內部實現,仍是將 double 類型轉為 String 類型; 這通常是將 double(或float)轉化為 BigDecimal 的首選方法;
如下代碼測試操作:
public class BigDecimalDemo {
public static void main(String[] args) {
Double v1 = 2.43;
Double v2 = 4.0;
System.out.println(new BigDecimal(v1));
System.out.println(new BigDecimal(v2));
System.out.println(new BigDecimal(v1.toString()));
System.out.println(new BigDecimal(v2.toString()));
System.out.println(BigDecimal.valueOf(v1));
System.out.println(BigDecimal.valueOf(v2));
}
}
以上輸出的結果是:
2.430000000000000159872115546022541821002960205078125
4
2.43
4.0
2.43
4.0
從結果可以看的出來直接 new BigDecimal()的情況會出現數據精准度丟失的情況
而. valueof 和 new 字符串的形式卻不會使精度丟失
我們可以看一下他的源碼:
/**
* Translates a {@code double} into a {@code BigDecimal}, using
* the {@code double}'s canonical string representation provided
* by the {@link Double#toString(double)} method.
*
* <p><b>Note:</b> This is generally the preferred way to convert
* a {@code double} (or {@code float}) into a
* {@code BigDecimal}, as the value returned is equal to that
* resulting from constructing a {@code BigDecimal} from the
* result of using {@link Double#toString(double)}.
*
* @param val {@code double} to convert to a {@code BigDecimal}.
* @return a {@code BigDecimal} whose value is equal to or approximately
* equal to the value of {@code val}.
* @throws NumberFormatException if {@code val} is infinite or NaN.
* @since 1.5
*/
public static BigDecimal valueOf(double val) {
// Reminder: a zero double returns '0.0', so we cannot fastpath
// to use the constant ZERO. This might be important enough to
// justify a factory approach, a cache, or a few private
// constants, later.
return new BigDecimal(Double.toString(val));
}
valueof 的形式是將 double 直接 tostring 為一個字符串的形式進行轉換的
BigDecimal 的大小比較
BigDecimal是Java里精確計算的類,下面說一下兩個BigDecimal對象大小,相等的判斷。
一般的對象用equals,但是BigDecimal比較特殊,舉個例子:
public static void main(String[] args) {
BigDecimal a = new BigDecimal("10.00");
BigDecimal b = new BigDecimal("10");
//equals方式
System.out.println(a.equals(b)); //結果為: false
//toPlainString再equals
System.out.println(a.toPlainString().equals(b.toPlainString())); //結果為: false
//longValue方式
System.out.println(a.longValue() == b.longValue()); //結果為: true
//compareTo
System.out.println(a.compareTo(b) == 0); //結果為: true
}
看似使用 Long 數據類型進行比較也可以但是我們看下一個例子:
public static void main(String[] args) {
BigDecimal a = new BigDecimal("10.300003");
BigDecimal b= new BigDecimal(10.300003);
System.out.println(b.equals(a)); //false
System.out.println(b.toPlainString().equals(a.toPlainString())); //false
System.out.println(b.longValue() == a.longValue()); //true
System.out.println(b.compareTo(a) == 0); //false
}
為什么compareTo方法不可以了,而longValue方式卻還是OK的。讓我們打印一下。
public static void main(String[] args) {
BigDecimal a = new BigDecimal("10.300003");
BigDecimal b= new BigDecimal(10.300003);
System.out.println(b.equals(a)); //false
System.out.println(b.toPlainString().equals(a.toPlainString())); //false
System.out.println(b.longValue() == a.longValue()); //true
System.out.println("b.longValue():"+b.longValue());
System.out.println("a.longValue():"+a.longValue());
System.out.println(b.compareTo(a) == 0); //false
}
而輸出的結果令我懵逼
false
false
true
b.longValue():10
a.longValue():10
false
我們可以看出longvalue 的結果是沒有小數點的所以對 BigDecimal 數據類型進行比較的時候還是使用"compareTo"方法
總結: 當我們需要使用BigDecimal 進行數據轉換時一定要注意轉換的數據類型以及大小比較的唯一方法我們可以對它的值進行<或者>的判斷如:
public static void main(String[] args) {
BigDecimal a = new BigDecimal("10.300003");
BigDecimal b= BigDecimal.valueOf(10.3);
System.out.println(b.compareTo(a) < 0); //true
System.out.println(b.compareTo(a) > 0); //false
}
最后:感謝大家的閱讀