2012-10-31 47 views
0

我在我的應用程序中做了很多浮點操作,我知道浮點操作不是100%準確的,這很好,但是當涉及到打印結果時我還沒有找到一種正確格式化的方法。JAVA浮點操作

例如

0.1 + 0.1 = 0.19999999999999999999999

Math.sin(Math.PI)=的1.2246E16代替0

和類似的東西1.000000000000000001

我正在尋找採取這些結果並獲得適當的四捨五入值的一般方法(以字符串形式)

這樣 0.1 + 0.1 = 0.19999999999999999999999 - > 0.2這一需要舍入

Math.sin(Math.PI)= 1.2246E16 - > 0

和類似的東西1.000000000000000001 - > 1;而這一個需要向下舍入

我也想避免在例如結果爲 1.1234567891234567或1.33333333333333的情況下丟失數據,結果應該保持不變。

+1

http://floating-point-gui.de/ – BalusC

+1

不可能。程序如何知道是否應該捨棄'0.1999999999999'(因爲它是'0.1 + 0.1'的結果)或不是(因爲它是'0.2 - 0.000000000001'的結果? – rolve

+0

'System.out.println(0.1+ 0.1)'產生「0.2」,順帶說一句 – DNA

回答

1

如果要避免使用格式設置,可以在打印結果之前將結果舍入爲固定精度,並使用Java會進行少量舍入來隱藏表示形式錯誤的事實。

例如到6位小數

public static double round6(double d) { 
    return Math.round(d * 1e6)/1e6; 
} 

round()結果和1e6,能精確表示。此外,「IEEE 754需要正確舍入:也就是說,四捨五入的結果就好像使用無限精確的算術計算該值,然後舍入」剩下的唯一誤差是表示誤差,因爲它取最接近的可表示值。 Java的toString()假定當你有一個double值,它的最小可表示值是一個更短的小數時,這就是你想看到的。

例如爲0.1的實際值是

System.out.println(new BigDecimal(0.1)); 

打印

0.1000000000000000055511151231257827021181583404541015625 

但Double.toString()傳遞該值時,它確定0.1將被轉換成此雙和所以這是它應該被顯示。

順便說一句在Java 6中有一個錯誤,它不使用最小位數。

for (int i = 1; i <= 9; i++) 
    System.out.print(i/1000.0 + " "); 
在Java中

6個打印

0.0010 0.0020 0.0030 0.0040 0.0050 0.0060 0.0070 0.0080 0.0090 

,並在Java 7個的打印

0.001 0.002 0.003 0.004 0.005 0.006 0.007 0.008 0.009 

我經常用printf如果性能不是關鍵的,如果是,我使用自定義例程將double寫入一個直接的ByteBuffer以達到一個固定的精度(有效地舍入它)由於它不創建任何對象,速度更快。

我還想避免在結果爲1.1234567891234567或1.33333333333333的情況下丟失數據,結果應該保持不變。

在這種情況下,直到需要顯示結果爲止,請不要舍入結果。

+0

爲什麼不會給你四捨五入錯誤? –

+0

我不知道它的一個例子。我認爲這是因爲在將整個數字除以另一個整數時可以得到多少舍入誤差是有限的。 –

+0

@TobiasRitzau包含了一個少手浪潮的答案;) –

1

使用例如System.out.printf("%.6f", myFloat)的格式。

+0

不使用printf – aviran

+0

@aviran爲什麼你不想使用printf? btw +1 –

+0

'String.format()'採用相同的參數,併爲您提供'String',其他類似的格式化選項也被加載。 –

0

如果您想避免丟失小數,請使用BigDecimal而不是float。更慢但更準確。

+0

BigDecimal如何使用像sin/cos/log/ln這樣的函數? 它不是準確的計算,我可以與結果1.9999生活,但是當我打印回來,我想它是2.0,有什麼建議嗎? – aviran