使用BigDecimal解决精度问题

先来看一下以下几行代码运行的结果:

public class Test{
    public static void main(String[] arg){
        int a=3;
        double b=3.3;
        double c=a*b;
        System.out.println(c);
    }
}

运行结果:

9.899999999999999

为什么不是输出9.9呢?是由于java的精度损失造成的。详细原因见http://www.cnblogs.com/backwords/p/9826773.html

所以需要用BigDecimal类来处理精度缺失问题。

BigDemical是Number类的子类。要使用BigDemical做运算首要先将其他类型的数字转换成BigDemical类,那么就要用到BigDemical的构造方法。BigDemical提供很多构造方法。例如:

public BigDecimal(int val)

public BigDecimal(long val)

public BigDecimal(double val)

public BigDecimal(String val)

注意,我们看到,没有Float类型的参数。但是,我们知道,Float类型的变量可以自动转型为Double,那么可否用public BigDecimal(double val)这个构造方法去接收Float类型的参数呢?虽然可以,但是这样会导致精度的损失。因为Float只有32位,Double有64位。不信的话看代码:

float q=3.33f;
double w=q;
System.out.println(w);

输出:

3.3299999237060547

那么,如果是一个double类型的变量就可以用public BigDecimal(double val)了么?还是会导致精度的损失。因为3.33无法准确的用二进制来表示。所以建议把double类型或者float类型的变量转化成String类型,然后用public BigDecimal(String val)。可以直接用

public static BigDecimal valueOf(double val)

合成这两步。但是把double类型的变量或者float类型的变量转化为String这一步骤又可能出现精度损失。因为Double.toString()会使用一定的精度来四舍五入double。Double.toString(0.1000000000000000055511151231257827021181583404541015625)输出的事实上是"0.1"。所以,如果你希望BigDecimal能够精确地表示你希望的数值,那么一定要使用字符串来表示小数,并传递给BigDecimal的构造函数。如果你使用Double.toString来把double转化字符串,然后调用BigDecimal(String),这个也是不靠谱的,它不一定按你的想法工作。参考博客https://www.cnblogs.com/wangzhongqiu/p/9542145.html

完成构造以后,就可以调用BigDecimal的方法进行运算:

public BigDecimal add(BigDecimal augend)
public BigDecimal subtract(BigDecimal subtrahend)
public BigDecimal multiply(BigDecimal multiplicand)
public BigDecimal divide(BigDecimal divisor)

示例:

import java.math.BigDecimal;

public class Test{

    public static void main(String[] arg){
        int a=3;
        double b=0.3;
        System.out.println(BigDecimal.valueOf(b).add(new BigDecimal(a)));
        System.out.println(BigDecimal.valueOf(b).subtract(new BigDecimal(a)));
        System.out.println(BigDecimal.valueOf(b).multiply(new BigDecimal(a)));
        System.out.println(BigDecimal.valueOf(b).divide(new BigDecimal(a)));
        System.out.println("******************");
        System.out.println(b+a);
        System.out.println(b-a);
        System.out.println(b*a);
        System.out.println(b/a);
    }
}

输出:

3.3
-2.7
0.9
0.1
******************
3.3
-2.7
0.8999999999999999
0.09999999999999999

注意,使用divede()方法时,若结果是无限小数,会抛出ArithmeticException异常。这时可以使用以下两种方法代替:

public BigDecimal divide(BigDecimal divisor,RoundingMode roundingMode)
public BigDecimal divide(BigDecimal divisor,int scale,RoundingMode roundingMode)

其中 scale表示保留几位小数,roundingMode表示舍入的模式。详细模式介绍可参考API。

BigDecimal还有其他常用方法:

public BigDecimal setScale(int newScale)//设置四舍五入到小数点几位
public double doubleValue()//将BigDecimal转换为double类型
public int intValue()//将BigDecimal转换为int类型

 

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值