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 阅读(8715)
评论(4) 编辑 收藏 所属分类:
Java