2014-01-16 85 views
-1

這是我遇到的問題。我有一個CSV文件,我讀的是4381個小數,大部分在-5和5之間。他們的例子是0.00000822, -0.20929117, -2.204, 4.88490078Java小數大於BigDecimal?

在我用Java編寫的程序中,我正在讀取CSV文件並將所有4381號碼加在一起得到一筆款項。但是,我得到的總和甚至沒有接近正確的數字。如果我使用=SUM(C:C)將Excel中的數字列添加到Excel中,我會得到10.77918727。如果我將它們加在我的程序中,我會得到-933.39114459。正如你所看到的,這些數字甚至不是很接近。我不知道Excel的價值是否正確,但我知道數據無法正確-933。

問題是,如果我使用另一個CSV文件中較小的一組數字,那麼這些數字會正確合計,所以我確信我的程序正確地進行了添加。無論如何,我已經將我正在使用的代碼添加到下面的代碼中。

因爲數字與較小的樣本加起來正確的,我能想到的唯一的事情會導致出現這樣計算不正確的總和我在我的sum變量(稱爲gainLoss)用完位。這使我想到了我的問題:有沒有一種方法可以用Java中比使用BigDecimal更多的位來表示小數位?我已經在使用BigDecimal,它似乎不提供足夠的位,除非我做錯了什麼。

一個想法,我不得不避開BigDecimal的限制是手動用科學記數法像BigDecimal的做法,但我會用一個BigDecimal爲基礎,一個BigDecimal爲標尺。唯一的問題是,如果有更好的方法來表示更大的數字,那麼我想避免的工作似乎很多。

讓我知道是否有更好的方法來表示數字需要大量的位或者如果我做錯了什麼。我也會採取任何建議。

這裏是我使用添加的數字相加(減去所有我必須做的,首先要確定應加入一些支票)代碼:

// gainLoss is the sum of all the numbers 
BigDecimal gainLoss = new BigDecimal(0.0); 

// data is a 2D Object array of all the data from the CSV file. 
// The 2nd column in data is filled with BigDecimal objects 
for (int i = 1; i < data.length; i++) // for each data row in data (excluding the header row) 
{ 
    // set rowAmt to the value of the number in the current row of the CSV file 
    BigDecimal rowAmt = (BigDecimal)data[i][2]; 

    // add this row's value to gainLoss 
    gainLoss = gainLoss.add(rowAmt); 
} 

編輯:以下是完整的代碼我使用來計算的總和,如要求:

public static BigDecimal calcGainLoss(Object[][] data, Calendar startCal, Calendar endCal) 
{ 
    BigDecimal gainLoss = new BigDecimal("0.0"); 
    for (int i = 1; i < data.length; i++) // for each data row in data 
    { 
     int lineNum = i + 1; 
     System.out.println("Line " + lineNum + ", i " + i + ": " + gainLoss.toString()); 
     // Load the important values into memory 
     String rowType = (String)data[i][4]; 
     BigDecimal rowAmt = (BigDecimal)data[i][2]; 
     Calendar rowDate = (Calendar)data[i][1]; 

     // Check if this row should be included in the calculations based on its row type 
     if (rowType.equalsIgnoreCase("cancel")) // if this was a cancelled transaction 
     { 
      continue; // move on to the next row 
     } 

     // Check if this row should be included in the calculations based on its date 
     boolean rowIsIncludedDate = false; // whether this row is within the given date range 
     if ((startCal == null) && (endCal == null)) // if no start or end date was given 
     { 
      rowIsIncludedDate = true; 
     } 
     else if ((startCal == null) && (!rowDate.after(endCal))) // if no start date was given and the current row's date is before or equal to the end date 
     { 
      rowIsIncludedDate = true; 
     } 
     else if ((endCal == null) && (!rowDate.before(startCal))) // if no end date was given and the current row's date is equal to or after the start date 
     { 
      rowIsIncludedDate = true; 
     } 
     else if ((!rowDate.before(startCal)) && (!rowDate.after(endCal))) // if both dates were given and the current row's date is equal to or after the start date and equal to or before the end date 
     { 
      rowIsIncludedDate = true; 
     } 

     if (!rowIsIncludedDate) // if this row should not be included in the calculation because its date is outside of the requested range 
     { 
      continue; // go on to the next row 
     } 

     // Add the current row's value to the current sum 
     gainLoss = gainLoss.add(rowAmt); 
     System.out.println("Adding " + rowAmt.toString()); 
    } 

    return gainLoss; 
} 
+0

你學到了通過你的代碼調試器步進什麼? –

+0

我其實從來沒有嘗試過。我現在要做。 – cmasupra

+0

或者通過插入打印輸出,以便在運行過程中觀察過程? (你確定你已經正確地填充了數據[] []嗎?) – keshlam

回答

0

這是一個長鏡頭,但有時如果數字有很大的不同幅度的,你可以遇到這樣的問題。解決的辦法是首先對數字進行排序,然後先取大對數之間的差異。你將如何遇到麻煩,例如:

10E38 + 5 - 10E38 

將返回5.但是

10E38 - 10E38 + 5 

0,而不是將返回5(從左至右評價,權當)。當你按照正確的順序進行操作時,你不會因爲將它添加到10E38中而失去5個位(沒有足夠的位來存儲它)。

儘管如此,「真實世界的數據」引起的舍入誤差與您所經歷的一樣大是很常見的。您可能錯誤地解釋Excel數據。由於您現在已經闡明瞭在另一列中包含單詞「取消」時您沒有添加某些數字,因此您可能需要確認事實上,通過計算以下公式可以得到與Excel不同的答案:

=SUM(C1:C4381) - SUMIF(E1:E4381, "cancel", C1:C4381) 
  • 基本上,這就是說「總和所有元素,然後用'旁邊的'取消'減去那些元素」。

它可能會變成你的代碼是正確的,你對答案(或數據)的假設是錯誤的...

+1

這不應該發生在'BigDecimal'上,因爲它只佔用它需要的位數。當然,這取決於數據是如何找到他們的方式進入'data [] []'數組 - 也許OP在它們變成'BigDecimal'之前將它們轉換爲'double',或類似的東西。 –

+0

是的 - 正如我所說「這是一個遠投」。但是,由於OP說他確信陣列中的數字是正確的,所以你不得不懷疑...... – Floris

+0

這也取決於如何使用BigDecimal ...... – Ned