您的位置:首页 > 编程语言 > Java开发

Java -- BigDecimal类

2017-07-21 21:14 344 查看
1、概述

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

2、简介

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

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类型

intVa
4000
lue(): 将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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Java-SE