浮点数精度丢失问题的解决

大家都知道,0.1加0.1结果为0.2,但是下面程序的运行结果和预想的结果有一些差距,

System.out.println("0.05+0.01 = "+(0.05+0.01));
System.out.println("1.0-0.42 = "+(1.0-0.42));
System.out.println("2.0*3.10 = "+(2.0*3.10));
System.out.println("123.3/100 = "+(123.3/100));

运行结果

0.05+0.01 = 0.060000000000000005
1.0-0.42 = 0.5800000000000001
2.0*3.10 = 6.2
123.3/100 = 1.2329999999999999

从上面的结果可以看出,double类型发生了精度丢失的问题,尤其在进行算术运算的时候更容易发生这样的问题。
为了能够精确的表示,计算浮点数,java提供了BigDecimal类来解决浮点数精度丢失的问题。
现贴出BigDecimal类的一个构造函数供大家参考,可以从中找到浮点数精度丢失的解决办法
这里写图片描述

解决方法:

相信从上面的文档大家也已经找出了解决方法,
在需要精确的表示两位小数时我们需要把他们转换为BigDecimal对象,然后再进行运算。
另外需要注意
使用BigDecimal(double val)构造函数时仍会存在精度丢失问题,建议使用BigDecimal(String val)这就需要先把double转换为字符串然后在作为BigDecimal(String val)构造函数的参数。转换为BigDecimal对象之后再进行加减乘除操作,这样精度就不会出现问题了。这也是为什么有关金钱数据存储都使用BigDecimal。
如果必须使用double浮点数作为BigDecimal构造器的参数时,不要直接将该double浮点数作为构造器参数创建BigDecimal对象,而是应该通过BigDecimal.valueOf(doubel value)静态方法来创建BigDecimal对象。

BigDecimal类的方法:

BigDecimal类的一些常用方法可以在java1.8API帮助文档里查看;
打开文档->搜索->输入BigDecimal,在右边就可以看到BigDecimal类的所有方法;
下面程序分别使用BigDecimal的基本运算:

package Base3;

import java.math.BigDecimal;

public class BIgDecimalTest {
    public static void main(String[] args){
        BigDecimal b1 = new BigDecimal("0.05");
        BigDecimal b2 = BigDecimal.valueOf(0.05);
        BigDecimal b3 = new BigDecimal(0.05);
        System.out.println("使用String作为BigDecimal构造器参数:");
        System.out.println("0.05+0.01 = "+b1.add(b2));
        System.out.println("0.05-0.01 = "+b1.subtract(b2));
        System.out.println("0.05*0.01 = "+b1.multiply(b2));
        System.out.println("0.05/0.01 = "+b1.divide(b2));
        System.out.println("使用double作为BigDecimal构造器参数:");
        System.out.println("0.05+0.01 = "+b3.add(b2));
        System.out.println("0.05-0.01 = "+b3.subtract(b2));
        System.out.println("0.05*0.01 = "+b3.multiply(b2));
        System.out.println("0.05/0.01 = "+b3.divide(b2));
    }
}

运算结果

使用String作为BigDecimal构造器参数:
0.05+0.01 = 0.10
0.05-0.01 = 0.00
0.05*0.01 = 0.0025
0.05/0.01 = 1
使用double作为BigDecimal构造器参数:
0.05+0.01 = 0.10000000000000000277555756156289135105907917022705078125
0.05-0.01 = 2.77555756156289135105907917022705078125E-18

从上面程序运行结果可以看出BigDecimal进行算术运算的效果,而且可以看出创建BigDecimal对像时,一定要使用String对象作为构造器参数,而不是直接使用double数字。
如果程序中要求对double浮点数进行基本运算,则需要先将double类型数字包装成BigDecimal对象,调用BigDecimal对象的方法执行运算后再转换成double型变量。这是一个比较繁琐的过程,可以考虑以BigDecimal为基础定义一个Arith工具类,该工具类代码如下:

package Base3;

import java.math.BigDecimal;

public class Arith {
    private static final int DEF_DIV_SCALE = 10;
    private Arith(){}
    public static double add(double v1,double v2){
        BigDecimal b1 = BigDecimal.valueOf(v1);
        BigDecimal b2 = BigDecimal.valueOf(v2);
        return b1.add(b2).doubleValue();
    }
    public static double sub(double v1,double v2){
        BigDecimal b1 = BigDecimal.valueOf(v1);
        BigDecimal b2 = BigDecimal.valueOf(v2);
        return b1.subtract(b2).doubleValue();
    }
    public static double mul(double v1,double v2){
        BigDecimal b1 = BigDecimal.valueOf(v1);
        BigDecimal b2 = BigDecimal.valueOf(v2);
        return b1.multiply(b2).doubleValue();
    }
    public static double div(double v1,double v2){
        BigDecimal b1 = BigDecimal.valueOf(v1);
        BigDecimal b2 = BigDecimal.valueOf(v2);
        return b1.divide(b2, DEF_DIV_SCALE, BigDecimal.ROUND_HALF_UP).doubleValue();
    }
    public static void main(String[] args){
        System.out.println("0.05+0.01 = "+Arith.add(0.05, 0.01));
        System.out.println("1.0-0.42 = "+Arith.sub(1.0, 0.42));
        System.out.println("4.015*100 = "+Arith.mul(4.015, 100));
        System.out.println("123.3/100 = "+Arith.div(123.3, 100));
    }
}

运行结果

0.05+0.01 = 0.06
1.0-0.42 = 0.58
4.015*100 = 401.5
123.3/100 = 1.233
  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值