?
2006
年9月13日
星期三
不要用float和double來進行精確的小數計算
?
什么?難道它們不就是為了小數計算而生的么?在我看到
effective java
-
item31
的時候,發出了這個孤陋寡聞的疑問。
?
知其然:
為什么說不能用
float
和
double
來進行精確小數計算呢?
試試執行這樣的語句:
System.out.println(
1.03
?
-
?.
42
);
//
答案是0.6100000000000001?!
System.out.println(
1.00
?
-
?
9
*
.
10
);
//
答案是0.09999999999999995?!
你會發現結果和你的小學數學課程有沖突。
?
知其所以然
之所以出現這樣的奇怪答案,是因為
float
和
double
不能精確的表達
0.1
,或者任何
10
的負
n
次方。他們是設計來進行科學和工程上的計算,提供精確的近似值的。它們在涉及金融方面的計算則是不在行的。因為金融方面要求絕對的精確。
?
解決方法
用
BigDecimal
,
int
或者
long
。
?
?
BigDecimal?bd?
=
?
new
?BigDecimal(
"
1.00
"
);
?
?
把所有牽涉到的小數都以這種方式轉變為
BigDecimal
對象,然后用它提供的方法進行計算。
你就得到了精確的計算結果,隨之而來有兩個小缺點,一個。。。很顯然,就是比直接用原始類型要麻煩,也不能用
+,-,*,/
這些直觀的符號了;第二個就是速度會慢一點,如果不是用于大量的循環之中,則不是那么要緊。不過,你也同時得到了一個好處,
BigDecimal
類還帶了豐富的舍入方法,也是不錯的。
如果小數位本身不長,則可以用
int
或者
long
來替代,我想你明白這個方法是什么意思的。在速度必須很快的位置,你又不介意自己看著小數點位,這個還是可用的,但如果數字本身超過了
18
位,就只能用
BigDecimal
了。
?
Wednesday, September 13, 2006
Don’t use float and double when exact answers are required
?
What? Aren’t calculating decimal are what they are design for? I made such an ignorant question when I first read effective java-item31.
?
The phenomenon:
Why we can’t use float and double to calculate decimal when exact results are required?
Try the following statements:
?
System.out.println(
1.03
?
-
?.
42
);
//
the?answer?is?0.6100000000000001?!
System.out.println(
1.00
?
-
?
9
*
.
10
);
//
the?answer?is?0.09999999999999995?!
?
You will find the answers are not agree with what you have learned in primary school.
?
The reason:
It is all because float and double can not represent exactly 0.1, or any other negative power of ten. They are designed for scientific and engineering calculation which demands accurate approximation. And they are ill-suited for monetary calculations.
?
The solution:
Use BigDecimal, int or long instead.
?
?
BigDecimal?bd?
=
?
new
?BigDecimal(
"
1.00
"
);
?
?
Transfer all decimal numbers involved in the calcution into BigDecimal objects as above, and then use them to calcute for a exact result, following with two disadvantages, the first, obviously, less convenient than using primitive types, all notations like +,-,*,/ can not be applied neither; the second, it will be slower, which can be ignored if it was not used in a heavily repeated loop. But you also get one merit which comes from the fact that BigDecimal carrys quite a lot of rounding methods.
If the quantity is not big, you can use int or long instead, you surely understand how to implement the idea. In performance critical section, and you don’t mind keeping track the of the decimal point yourself, this is feasible. But you have not choice if the quantity is over 18 digits, only BigDecimal is available.
posted on 2006-09-13 19:23
Ye Yiliang 閱讀(8727)
評論(4) 編輯 收藏 所屬分類:
Java