Java中的类型float、double用来作计算会有精度丢失问题,下面来看下面的示例。java
public static void main(String[] args) {
数据库
test1();
spa
test2();
code
}
ci
private static void test1() {
class
double totalAmount = 0.09;
test
double feeAmount = 0.02;
二进制
double tradeAmount = totalAmount - feeAmount;
float
System.out.println(tradeAmount);
程序
}
上面的程序输出结果是多少?
0.07?非也!
正确的结果是:
0.06999999999999999
为何是这样?
浮点数可能丢失精度,浮点十进制数一般没有彻底相同的二进制的表示形式,这是CPU所采用的浮点数据表示形式的反作用。为此,可能会有一些精度丢失,而且一些浮点运算可能会产生未知的结果。
浮点运算不多是精确的,只要是超过精度能表示的范围就会产生偏差。因此,在使用float、double做精确运算的时候必定要特别当心,除非能容忍精度丢失,否则产生的偏差也是会形成双方对帐不一致的结果。
在《Effective Java》这本书中也提到这个原则,float和double只能用来作科学计算或者是工程计算,在商业计算中咱们要用 java.math.BigDecimal。
BigDecimal适合更精度的运算,也提供了丰富的操做符类型,小数位控制,四舍五入规则等。
不过,使用BigDecimal不当也有精度丢失的状况,如double的构造方法:
BigDecimal(double val)
再来看这个示例:
private static void test2() {
double totalAmount = 0.09;
double feeAmount = 0.02;
BigDecimal tradeAmount = new BigDecimal(totalAmount).subtract(new BigDecimal(feeAmount));
System.out.println(tradeAmount);
}
输出:
0.0699999999999999962529972918900966760702431201934814453125
这个精度就更恐怖了。。
因此,必定要使用String的构造方法:
BigDecimal(String val)
private static void test3() {
double totalAmount = 0.09;
double feeAmount = 0.02;
BigDecimal tradeAmount = new BigDecimal(String.valueOf(totalAmount))
.subtract(new BigDecimal(String.valueOf(feeAmount)));
System.out.println(tradeAmount);
}
金额运算尽可能使用BigDecimal(String val)进行运算。
数据库存储金额,通常有整型和浮点型两种存储方式。若是是有汇率转换的,建议使用浮点数decimal进行存储,能够灵活的控制精度,decimal直接对应java类型BigDecimal。固然,用整数存储分这种形式也能够,转帐的时候单位为元而若是忘了转换分为元,那就悲剧了。