2012-09-12 33 views
38

在Java中,我想採用double值並將其轉換爲BigDecimal,並將其值以特定精度打印出來。將double轉換爲BigDecimal並設置BigDecimal Precision

import java.math.BigDecimal; 
public class Main { 
    public static void main(String[] args) { 
     double d=-.00012; 
     System.out.println(d+""); //This prints -1.2E-4 

     double c=47.48000; 
     BigDecimal b = new BigDecimal(c); 
     System.out.println(b.toString()); 
     //This prints 47.47999999999999687361196265555918216705322265625 
    } 
} 

它打印這個巨大的東西:

47.47999999999999687361196265555918216705322265625

,而不是

47.48

我正在做BigDecimal轉換的原因有時候雙值會包含很多小數位(即-.000012)以及何時將double轉換爲String將產生科學記數法-1.2E-4。我想以非科學記數法存儲字符串值。

我想讓BigDecimal總是有兩個精度單位:「47.48」。 BigDecimal是否可以限制轉換爲字符串的精度?

BigDecimal b = new BigDecimal(d, MathContext.DECIMAL64); 

只需選擇您需要的情況下:

+1

注:BigDecimal的也有時會使用科學記數法(相信對於數<10^-6) – assylias

回答

36

如果使用其他MathContext它打印47.48000。

+12

使用雙構造不推薦。 – assylias

+1

http://stackoverflow.com/questions/1056722/why-is-the-bigdecimaldouble-d-construction-still-around –

+14

BigDecimal b = BigDecimal.valueOf(d); – rvazquezglez

15

你想試試String.format("%f", d),它會用十進制表示法打印出你的雙倍數。根本不要使用BigDecimal

關於精度的問題:你是第一個存儲47.48double c,進而實現從doubleBigDecimal。精確度的損失分配給c。你可以做

BigDecimal b = new BigDecimal("47.48") 

爲了避免失去任何精度。

+1

+1人應該(幾乎)從不使用雙重構造函數。 – assylias

5

它打印出double的實際值。

Double.toString(),這double S轉換到String S,確實打印輸入準確的十進制值 - 如果x是你的雙重價值,它打印出足夠精確的數字是x最接近double的值它打印。

重點是不是double正好是47.48。將商店值加倍爲二進制分數,而不是小數,因此它不能存儲精確的小數值。 (這就是BigDecimal的作用!)

3

String.format語法可以幫助我們將double和BigDecimals轉換爲任何精度的字符串。

這java代碼:

double dennis = 0.00000008880000d; 
System.out.println(dennis); 
System.out.println(String.format("%.7f", dennis)); 
System.out.println(String.format("%.9f", new BigDecimal(dennis))); 
System.out.println(String.format("%.19f", new BigDecimal(dennis))); 

打印:

8.88E-8 
0.0000001 
0.000000089 
0.0000000888000000000 
63

這種行爲的原因是打印在字符串的精確值 - 你的預期可能不算什麼,但是這存儲在內存中的實際值 - 這只是浮點表示的限制。

據javadoc的不同,BigDecimal(double val)將構造函數的行爲可能是意想不到的,如果你不考慮這個限制:

此構造方法的結果有一定的不可預知的。一個 可能會認爲在Java中寫入new BigDecimal(0.1),創建一個 BigDecimal正好等於0.1(1未測量的值,與 比例爲1),但它實際上是等於 0.1000000000000000055511151231257827021181583404541015625。這是因爲0.1不能完全表示爲雙精度(或者對於任何有限長度的二元分數)。因此,傳遞給構造函數的值 並不完全等於 0.1,儘管如此。

所以你的情況,而不是使用

double val = 77.48; 
new BigDecimal(val); 

使用由BigDecimal.valueOf返回

BigDecimal.valueOf(val); 

值等於從Double.toString(double)調用產生的。

+2

今天進入完全相同的問題,這是恕我直言最適合的答案!謝謝! – PhilDulac

+1

我建議在'BigDecimal.valueOf(val)'之後添加'.stripTrailingZeros()'來省略Tracing零。例如:'BigDecimal.valueOf(15.0).stripTrailingZeros();' - > 15(而不是15.0,如果你不調用'。stripTrailingZeros()' – pierrefevrier

3

爲什麼不:

b = b.setScale(2, RoundingMode.HALF_UP); 
+0

爲什麼不是BigDecimal b = new BigDecimal(c).setScale(2,BigDecimal.ROUND_HALF_UP); – zee

1
BigDecimal b = new BigDecimal(c).setScale(2,BigDecimal.ROUND_HALF_UP); 
0

在Java 9已經過時了以下內容:

BigDecimal.valueOf(d). setScale (2, BigDecimal. ROUND_HALF_UP );

改用:

BigDecimal.valueOf(d).setScale(2, RoundingMode.HALF_UP); 

實施例:

double d = 47.48111; 

    System.out.println(BigDecimal.valueOf(d)); //Prints: 47.48111 

    BigDecimal bigDecimal = BigDecimal.valueOf(d).setScale(2, RoundingMode.HALF_UP); 
    System.out.println(bigDecimal); //Prints: 47.48