2012-06-13 48 views
1

我目前正在開發一個java程序,它需要向一個雙變量添加一個小的常量值,例如0.00000000001,例如。位置。但是,當我運行代碼時,對其進行調試,然後到達將0.00000000001添加到位置的位置,並在添加完成後檢查調試模式下的位置值。看來該位置沒有添加0.00000000001。例如,加入前的位置等於438.0,加入後的位置等於438.0。下面是簡單的代碼是什麼樣子在java中添加非常小的值

位置+ = 0.00000000001

任何想法一個例子嗎?提前致謝。

+0

http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg。 html – NPE

+1

什麼是位置類型? – David

回答

6

由於存儲方式的緣故,許多double值在Java中並不準確。精確的精度僅適用於某些值。這是因爲Java只能將十進制值存儲爲多個2^n(s)的組合。

如:1/4可以存儲爲2^-2,但1/3將存儲爲2^-2 + 2^-3+ 2^-4 +2^-5...,所以1/3是不完全準確的值的例子

如果你想有一個精確值,使用BigDecimal類:

http://docs.oracle.com/javase/7/docs/api/java/math/BigDecimal.html

+1

它們*精確,但它們沒有任意的精度,也不能精確地表示每個十進制數。 0.5的double值仍然恰好爲0.5。 –

+0

是的,我明白這一點。編輯。 –

+0

所以只是爲了澄清。雙打可以使用小數保持真正的大數,當他們變得非常小時,它們在處理小數時會遇到麻煩? – johns4ta

5

您需要使用BigDecimal更好的精度。

實施例:

BigDecimal test = new BigDecimal(438.0); 
test = test.add(new BigDecimal(0.0000000000001)); 
System.out.println(test); 
+0

所以只是爲了澄清。雙打可以使用小數保持真正的大數,當他們變得非常小時,它們在處理小數時會遇到麻煩? – johns4ta

+1

是的。這是因爲他們被表示的方式 - 作爲'2^n'。 –

+0

好的。我有計算機科學背景,所以我想我明白你想說什麼。謝謝。 – johns4ta

4

使用BigDecimal類。它具有任意的精度,並且能夠處理微小的值。

2

如果超出double的精度,則添加一個非常小的值無效。

for (double d = 438; d < 1e7; d *= 10) { 
    double location = d; 
    location += 0.00000000001; 
    System.out.println(location); 
} 

打印

438.00000000001 
4380.00000000001 
43800.00000000001 
438000.0 
4380000.0 
1

你可能運行到一個舍入誤差或下溢。我會嘗試使用BigDecimal進行任意精度。

1

你應該閱讀雖然http://firstclassthoughts.co.uk/java/traps/java_double_traps.html

這進入了Java商店和處理雙打和彩車,他們的意思是,當你使用,並比較他們什麼。

這是基本的情況下,「你看到的是不是你拿」

,如果你決定使用大十進制這有其自身的陷阱案件

http://firstclassthoughts.co.uk/java/traps/big_decimal_traps.html

這真的歸結爲什麼你想添加0.00000000001?

+0

只需要使兩個值的差值儘可能小時,它們本來就是相等的,在我的算法中,在某些情況下它們並不等於防止被零除。這只是我希望稍後修復的一個快速解決方案,但尚未找到合適的解決方案。 – johns4ta

0

還有一件事要添加到另一個答案。問題不在於值太小。更大的價值=更大的不確定性。看一個例子:

float x = 20000000.0f; 
for (int i = 0; i < 10000000; i++) { 
    x += 1; 
} 
System.out.println(x); // prints 20000000.0f, not 30000000.0f! 

所以,如果你使用的循環浮點數你永遠無法退出這個循環