BigDecimal类的的基本用法【附加:整除报错的解决方案】

一提到Java里面的商业计算,我们都知道不能用float和double,因为他们无法进行精确计算。但是Java的设计者给编程人员提供了一个很有用的类BigDecimal,他可以完善float和double类无法进行精确计算的缺憾。BigDecimal类位于java.maths类包下。首先我们来看下如何构造一个BigDecimal对象。它的构造函数很多,我挑最常用的两个来演示一下:一个就是BigDecimal(double val),另一个就是BigDecimal(String str)。这两个看上去没什么太大区别,但是正像API描述中说的那样:

/*The results of this constructor can be somewhat unpredictable. One might assume that 
new BigDecimal(.1) is exactly equal to .1, but it is actually equal 
to .1000000000000000055511151231257827021181583404541015625. This is so because .1 
cannot be represented exactly as a double (or, for that matter, as a binary fraction 
of any finite length). Thus, the long value that is being passed in to the constructor 
is not exactly equal to .1, appearances nonwithstanding.
The (String) constructor, on the other hand, is perfectly predictable: new BigDecimal
(".1") is exactly equal to .1, as one would expect. Therefore, it is generally 
recommended that the (String) constructor be used in preference to this one.*/


也就是说利用double作为参数的构造函数,无法精确构造一个BigDecimal对象,需要自己指定一个上下文的环境,也就是指定精确位。而利用String对象作为参数传入的构造函数能精确的构造出一个BigDecimal对象。请看下面的代码:

import java.math.*;

public class TestBigDecimal {
    public static void main(String args[]){
        BigDecimal bd = new BigDecimal("10.123");
        BigDecimal bd1 = new BigDecimal(10.123);
        

        System.out.println(bd +"/n"+ bd1);

    }
}

输出:

10.123
10.1229999999999993320898283855058252811431884765625

所以我们在选择构造函数时,要看具体需求而定。

另外,很多人会问到怎么将基本类型,如int,float,double,long,和BigDecimal对象相互转换。

很简单:

基本类型通过构造函数转换成对应的BigDecimal对象,而BigDecimal类提供了诸如intValue(), floatValue(), doubleValue(), longValue()方法来将BigDecimal对象转换成对应的值。

关于BigDecimal是如何计算的,我以论坛中一个人的提问帖子为例,来简单的写出BigDecimal的运算方法。

题目是:李白无事街上走,提壶去买酒。遇店加一倍,见花喝一斗,五遇花和店,喝光壶中酒,试问李白壶中原有多少斗酒?

这道题应该是从后往前推,并且要逆运算,最后得出原有酒的体积。

import java.math.*;

public class Libai {
    public static void main(String args[]){
        BigDecimal volumn = new BigDecimal("0");
        
        for (int i=0; i<5;  i++){           
            volumn = volumn.add(new BigDecimal("1"));
            volumn = volumn.divide(new BigDecimal("2"));
        }
        
        System.out.print(volumn);
    }
}

结果:0.96875

金额的数据类型是BigDecimal
通过BigDecimal的divide方法进行除法时当不整除,出现无限循环小数时,就会抛异常的。

异常如下:

java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result. at java.math.BigDecimal.divide(Unknown Source) 


应用场景:一批中供客户的单价是1000元/年,如果按月计算的话1000/12=83.3333333333....

解决之道:就是给divide设置精确的小数点divide(xxxxx,2, BigDecimal.ROUND_HALF_EVEN)

在 java中, 四舍五入通过 BigDecimal 来实现。一定要注意:BigDecimal is Immutable。也就是跟String一样,对前一个的修改,比如setScale(), add()等都会返回一个新的BigDecimal.四舍五入舍入模式是 BigDecimal.ROUND_HALF_UP 

下面贴上一张图:

 

我来解释:

roundMode是指舍位时候的模式,传参数的时候用BigDecimal.ROUND_XXXX_XXX

ROUND_CEILING:   舍位时往正无穷方向移动   1.1-> 2   1.5-> 2   1.8-> 2   -1.1-> -1   -1.5-> -1   -1.8-> -1 
ROUND_DOWN:向0的方向移动 1.1-> 1   1.5-> 1   1.8-> 1   -1.1-> -1   -1.5-> -1   -1.8> -1 
ROUND_FLOOR:与CEILING相反,往负无穷   1.1-> 1   1.5-> 1   1.8-> 1   -1.1-> -2   -1.5-> -2   -1.8-> -2 
ROUND_HALF_DOWN:以5为分界线,或曰五舍六入 1.5-> 1   1.6-> 1   -1.5-> -1   -1.6-> -2   
ROUND_HALF_EVEN:同样以5为分界线,如果是5,则前一位变偶数1.15-> 1.2   1.16-> 1.2   1.25-> 1.2   1.26-> 1.3 
ROUND_HALF_UP:最常见的四舍五入 
ROUND_UNNECESSARY:无需舍位 
ROUND_UP:与ROUND_DOWN,远离0的方向 1.1-> 2   1.5-> 2   1.8-> 2   -1.1-> -2   -1.5-> -2   -1.8-> -2 

具体精确到几位因该采用 
商=被除数.devide(除数,保留小数位数,精确方法) 


 

这篇文章我亲生体会的。这个对象相当的好用,大家想了解更加深入点的话可以去查看API

你可能感兴趣的:(热门技术,Thinking,in,java读后感)