Java -- BigDecimal类

1、概述
Java在java.math包中提供的API类BigDecimal,用来对超过16位有效位的数进行精确的运算。float和double只能用来做科学计算或者是工程计算,在商业计算中往往要求结果精确,此时就要用到java.math.BigDecimal。BigDecimal所创建的是对象,我们不能使用传统的+、-、*、/等算术运算符直接对其对象进行数学运算,而必须调用其相对应的方法。方法中的参数也必须是BigDecimal的对象。

2、简介
BigDecimal 由任意精度的整数非标度值 和32 位的整数标度 (scale) 组成。如果为零或正数,则标度是小数点后的位数。如果为负数,则将该数的非标度值乘以 10 的负scale 次幂,即 BigDecimal表示的数值是(unscaledValue × 10scale )。

3、方法
① BigDecimal一共有4个常用构造方法

BigDecimal(int) 创建一个具有参数所指定整数值的对象。
BigDecimal(double) 创建一个具有参数所指定双精度值的对象。
BigDecimal(long) 创建一个具有参数所指定长整数值的对象。
BigDecimal(String) 创建一个具有参数所指定以字符串表示的数值的对象。

注:
参数类型为double的构造方法的结果有一定的不可预知性
如:newBigDecimal(0.1)所创建的BigDecimal实际上等于0.1000000000000000055511151231257827021181583404541015625。
如果要进行精确转换:
1) Double.toString(double)–>BigDecimal(String)构造方法
2) BigDecimal.valueOf(double val)

② BigDecimal 的运算方式 不支持 + - * / 这类的运算 它有自己的运算方法

BigDecimal add(BigDecimal augend) 加法运算
BigDecimal subtract(BigDecimal subtrahend) 减法运算
BigDecimal multiply(BigDecimal multiplicand) 乘法运算
BigDecimal divide(BigDecimal divisor) 除法运算

BigDecimal 加减乘除运算并返回double类型数据范例

public class Arith {
    /**
     * 提供精确加法计算的add方法
     * @param value1 被加数
     * @param value2 加数
     * @return 两个参数的和
     */
    public static double add(double value1,double value2){
        BigDecimal b1 = new BigDecimal(Double.valueOf(value1));
        BigDecimal b2 = new BigDecimal(Double.valueOf(value2));
        return b1.add(b2).doubleValue();
    }

    /**
     * 提供精确减法运算的sub方法
     * @param value1 被减数
     * @param value2 减数
     * @return 两个参数的差
     */
    public static double sub(double value1,double value2){
        BigDecimal b1 = new BigDecimal(Double.valueOf(value1));
        BigDecimal b2 = new BigDecimal(Double.valueOf(value2));
        return b1.subtract(b2).doubleValue();
    }

    /**
     * 提供精确乘法运算的mul方法
     * @param value1 被乘数
     * @param value2 乘数
     * @return 两个参数的积
     */
    public static double mul(double value1,double value2){
        BigDecimal b1 = new BigDecimal(Double.valueOf(value1));
        BigDecimal b2 = new BigDecimal(Double.valueOf(value2));
        return b1.multiply(b2).doubleValue();
    }

    /**
     * 提供精确的除法运算方法div
     * @param value1 被除数
     * @param value2 除数
     * @param scale 精确范围
     * @return 两个参数的商
     * @throws IllegalAccessException
     */
    public static double div(double value1,double value2,int scale) throws IllegalAccessException{
        //如果精确范围小于0,抛出异常信息
        if(scale<0){         
            throw new IllegalAccessException("精确度不能小于0");
        }
        BigDecimal b1 = new BigDecimal(Double.valueOf(value1));
        BigDecimal b2 = new BigDecimal(Double.valueOf(value2));
        return b1.divide(b2, scale).doubleValue();    
    }
}

③ doubleValue()
将BigDecimal 类型转换为double类型
同理可得:

floatValue(): 将BigDecimal 类型转换为float类型
longValue(): 将BigDecimal类型转换为long类型
intValue(): 将BigDecimal 类型转换为int类型

注:

以上方法在向小精度的类型转换时均存在精度丢失问题
intValue() 将丢弃此 BigDecimal 的所有小数部分,并且如果生成的 ” BigInteger” 太大而不适合用 int 表示,则仅返回 32 位低位字节。注意,此转换会丢失关于此 BigDecimal 值的总大小和精度的信息,并返回带有相反符号的结果。

④ setScale(int newScale, int roundingMode)
返回一个保留指定小数位的BigDecimal类型的值

  • newScale 保留BigDecimal的位数
  • roundingMode 有以下几种处理模式:

    1.setScale(1,BigDecimal.ROUND_UP)
    进位处理,2.35变成2.4 。舍入远离零的舍入模式。在丢弃非零部分之前始终增加数字

    2.setScale(1,BigDecimal.ROUND_DOWN):
    直接删除多余的小数位,如2.35会变成2.3 。接近零的舍入模式。

    3.setScale(1,BigDecimal.ROUND_CEILING)
    接近正无穷大的舍入模式。如果 BigDecimal 为正,则舍入行为与 ROUND_UP 相同;如果为负,则舍入行为与 ROUND_DOWN 相同。接近负无穷大的舍入模式。如果 BigDecimal 为正,则舍入行为与 ROUND_DOWN 相同;如果为负,则舍入行为与 ROUND_UP 相同

    4.setScale(1,BigDecimal.ROUND_HALF_UP)
    向上四舍五入,2.35变成2.4

    5.setScale(1,BigDecimal.ROUND_HALF_DOWN)
    向下四舍五入,2.35变成2.3

    6.setScaler(1,BigDecimal.ROUND_HALF_EVEN)
    向“最接近的”数字舍入,如果与两个相邻数字的距离相等,则向相邻的偶数舍入。如果舍弃部分左边的数字为奇数,则舍入行为与 ROUND_HALF_UP 相同;如果为偶数,则舍入行为与 ROUND_HALF_DOWN 相同。注意,在重复进行一系列计算时,此舍入模式可以将累加错误减到最小。

    7.setScaler(1,BigDecimal.ROUND_UNNECESSARY)
    断言请求的操作具有精确的结果,因此不需要舍入。如果对获得精确结果的操作指定此舍入模式,则抛出 ArithmeticException。

BigDecimal b1 = new BigDecimal("23.4567");
System.out.println(b1.setScale(2,BigDecimal.ROUND_HALF_UP));  // 23.46
System.out.println(b1.setScale(0,BigDecimal.ROUND_HALF_DOWN));  // 23

⑤ BigDecimal 的比较

  • max(BigDecimal val) : 返回此 BigDecimal 和 val 的最大值。
    min(BigDecimal val) : 返回此 BigDecimal 和 val 的最小值。
 BigDecimal b1 = new BigDecimal("23.7");
 BigDecimal b2 = new BigDecimal("28.7");
 System.out.println(b1.max(b2));   // 28.7
 System.out.println(b1.min(b2));   // 23.7
  • equals(Object x)
    比较此 BigDecimal 与指定的 Object 的相等性。
BigDecimal b1 = new BigDecimal("23");
BigDecimal b2 = new BigDecimal("23.0");
BigDecimal b3 = new BigDecimal("23.000");
System.out.println(b1.equals(b2));  // false
System.out.println(b1.equals(b3));  // false

很明显equals无法很好的比较两个BigDecimal,所以要用到compareTo()方法

  • compareTo(BigDecimal val)
    将此 BigDecimal 与指定的 BigDecimal 比较。
    当此 BigDecimal 在数字上小于、等于或大于 val 时,返回 -1、0 或 1。
BigDecimal b1 = new BigDecimal("23");
BigDecimal b2 = new BigDecimal("23.0");
BigDecimal b3 = new BigDecimal("23.000");
System.out.println(b1.compareTo(b2));  // true
System.out.println(b1.compareTo(b3));  // true

一般我们都是在if语句中使用,如:

if(b1.compareTo(b2) == -1) {  // b1<b2情况
}
if(b1.compareTo(b2) == 0) {  // b1=b2情况
}
if(b1.compareTo(b2) == 1) {  // b1>b2情况
}          

⑥ 常量
数字常量:

public static final BigDecimal ZERO
public static final BigDecimal ONE
public static final BigDecimal TEN

roundingMode 模式常量:

public final static int ROUND_UP =           0;

public final static int ROUND_DOWN =         1;

public final static int ROUND_CEILING =      2;

public final static int ROUND_FLOOR =        3;

public final static int ROUND_HALF_UP =      4;

public final static int ROUND_HALF_DOWN =    5;

public final static int ROUND_HALF_EVEN =    6;

public final static int ROUND_UNNECESSARY =  7;

更多方法参见 java API手册 java.math–>BigDecimal

4、总结

    (1)商业计算使用BigDecimal。
    (2)尽量使用参数类型为String的构造函数。
    (3) BigDecimal都是不可变的(immutable)的,在进行每一步运算时,都会产生一个新的对象,所以在做加减乘除运算时千万要保存操作后的值。
    (4)我们往往容易忽略JDK底层的一些实现细节,导致出现错误,需要多加注意。

参考:
http://blog.csdn.net/jackiehff/article/details/8582449
http://www.cnblogs.com/chenssy/archive/2012/09/09/2677279.html
另外可参考:http://zhangyinhu8680.iteye.com/blog/1536397

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值