Java -- BigDecimal类

来源:互联网 发布:2017农村淘宝 编辑:程序博客网 时间:2024/05/19 04:53

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.46System.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));  // falseSystem.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));  // trueSystem.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

原创粉丝点击