遇到问题,精度丢失
最近一年多的时间一直在做智能POS相关的应用,经常涉及到金额的运算.后台金额是按照元为单位保留两位小数的浮点类型,我在客户端接收的时候也是按照double类型保存的.后来在运算的时候发现了好多时候会出现精度丢失的情况.经过我研究最后总结了两个最佳实践.
最佳实践1
一句话,不用浮点类型.(long的取值范围为-9223372036854775808到9223372036854775807,一般能足够满足您对金额的需求)
若您的项目现在处在设计阶段,建议后台设计的时候就以分为单位,用长整形long返回接收,这样就能避免一系列的浮点类型进行运算产生的精度丢失问题.在页面上需要展示价格的时候转换成BigDecimal做运算设置保留两位小数即可:
long a=3680;
BigDecimal bigDecimal = new BigDecimal(a).setScale(2,BigDecimal.ROUND_HALF_UP)//ROUND_HALF_UP 四舍五入
.divide(new BigDecimal(100));
System.out.println(bigDecimal.toPlainString());
//以下描述均为JavaApi文档描述
System.out.println(new BigDecimal("1E14").toString());//返回此 BigDecimal 的字符串表示形式,如果需要指数,则使用科学记数法。
System.out.println(new BigDecimal("1E14").toPlainString());//返回不带指数字段的此 BigDecimal 的字符串表示形式。
System.out.println(new BigDecimal("1E14").toEngineeringString());//返回此 BigDecimal 的字符串表示形式,需要指数时,则使用工程计数法。
输出结果:
36.80
1E+14
100000000000000
100E+12
最佳实践2
若后台已经不方便修改,我们可以在json接收的时候以String的形式接收后台返回的浮点类型(重点,以String类型接收浮点变量).在用到计算的时候把string装换成BigDecimal运算,运算之后输出是转换成对应的格式即可.
有人可能会问BigDecimal的构造方法不是可以穿double类型吗,为什么要用string接收?原因就是double书本身就不是精确表示的,即使转换成BigDecimal也是不准确的,所以只能用BigDecimal里String类型的构造方法.如果使用double接收也可以使用Double.toString转换为字符串再转换成BigDecimal。看下下面两个例子就能看出来了
double a =