BigDecimal类:双精度浮点型变量double可以处理16位有效数。在实际应用中,需要对更大或者更小的数进行运算和处理。Java在java.math包中提供的API类BigDecimal,用来对超过16位有效位的数进行精确的运算。下面列出了BigDecimal类的主要构造器和方法:
构造器描述:
BigDecimal(int)创建一个具有参数所指定整数值的对象。
BigDecimal(double)创建一个具有参数所指定双精度值的对象。
BigDecimal(long)创建一个具有参数所指定长整数值的对象。
BigDecimal(String)创建一个具有参数所指定以字符串表示的数值的对象。
方法描述:
add(BigDecimal)BigDecimal对象中的值相加,然后返回这个对象。
subtract(BigDecimal)BigDecimal对象中的值相减,然后返回这个对象。
multiply(BigDecimal)BigDecimal对象中的值相乘,然后返回这个对象。
divide(BigDecimal)BigDecimal对象中的值相除,然后返回这个对象。
pow(int n)BigDecimal对象中的值乘幂,然后返回这个对象。
toString()将BigDecimal对象的数值转换成字符串。
doubleValue()将BigDecimal对象中的值以双精度数返回。
floatValue()将BigDecimal对象中的值以单精度数返回。
longValue()将BigDecimal对象中的值以长整数返回。
intValue()将BigDecimal对象中的值以整数返回。
valueOf()将float,double类型转换为BigDecimal
注意,由于一般数值类型,例如double,不能准确地代表16位有效数以上的数字,在使用BigDecimal时,应用BigDecimal(String)构造器创建对象才有意义。另外,BigDecimal所创建的是对象,我们不能使用传统的+、-、*、/等算术运算符直接对其对象进行数学运算,而必须调用其相对应的方法。方法中的参数也必须是BigDecimal的对象。
下面是BigDecimal的一些常用例子:
//创建BigDecimal对象
BigDecimal bigNumber = new BigDecimal("89.1234567890123456789");
BigDecimal bigRate = new BigDecimal(1000);
BigDecimal bigResult = new BigDecimal(); //对象bigResult的值为0.0
//对bigNumber的值乘以1000,结果赋予bigResult
bigResult = bigNumber.multiply(bigRate);
System.out.println(bigResult.toString());
//或者System.out.println(bigResult);
//显示结果:89123.4567890123456789000
//以双精度数返回bigNumber中的值
double dData = bigNumber.doubleValue();
System.out.println(dData); //结果:89.12345678901235
注意使用方法doubleValue()将对象bigNumber中的值以双精度数值返回时,将丢失数据的准确性。使用其他方法,如xxxValue()时均存在这个问题,使用时必须慎重。
BigDecimal用来对超过16有效位以上的数值进行运算和操作。所有的算术运算都通过调用其相应的方法进行。创建一个超过16有效位数的对象时,运用BigDecimal(String)才可避免丢失数字的精确度。
BigDecimal和格式化:
由于NumberFormat类的format()方法可以使用BigDecimal对象作为其参数,可以利用BigDecimal对超出16位有效数字的货币值,百分值,以及一般数值进行格式化控制。
java四舍五入:
import java.math.BigDecimal; //引入这个包
public class Test {
public static void main(String[] args) {
double i = 3.856;
// 舍掉小数取整
System.out.println("舍掉小数取整:Math.floor(3.856)=" + (int) Math.floor(i));
// 四舍五入取整
System.out.println("四舍五入取整:(3.856)="
+ new BigDecimal(i).setScale(0, BigDecimal.ROUND_HALF_UP));
// 四舍五入保留两位小数
System.out.println("四舍五入保留两位小数:(3.856)="
+ new BigDecimal(i).setScale(2, BigDecimal.ROUND_HALF_UP));
// 凑整,取上限
System.out.println("凑整:Math.ceil(3.856)=" + (int) Math.ceil(i));
// 舍掉小数取整
System.out.println("舍掉小数取整:Math.floor(-3.856)=" + (int) Math.floor(-i));
// 四舍五入取整
System.out.println("四舍五入取整:(-3.856)="
+ new BigDecimal(-i).setScale(0, BigDecimal.ROUND_HALF_UP));
// 四舍五入保留两位小数
System.out.println("四舍五入保留两位小数:(-3.856)="
+ new BigDecimal(-i).setScale(2, BigDecimal.ROUND_HALF_UP));
// 凑整,取上限
System.out.println("凑整(-3.856)=" + (int) Math.ceil(-i));
输出结果:
舍掉小数取整:Math.floor(3.856)=3
四舍五入取整:(3.856)=4
四舍五入保留两位小数:(3.856)=3.86
凑整:Math.ceil(3.856)=4
舍掉小数取整:Math.floor(-3.856)=-4
四舍五入取整:(-3.856)=-4
四舍五入保留两位小数:(-3.856)=-3.86
凑整(-3.856)=-3
关于setScale函数的:
setScale(1)表示保留一位小数,默认用四舍五入方式
setScale(1,BigDecimal.ROUND_DOWN)直接删除多余的小数位,如2.35会变成2.3
setScale(1,BigDecimal.ROUND_UP)进位处理,2.35变成2.4
setScale(1,BigDecimal.ROUND_HALF_UP)四舍五入,2.35变成2.4
setScale(1,BigDecimal.ROUND_HALF_DOWN)五舍六入,2.35变成2.3,2.36变成2.4
测试代码:
1.测试参数类型为double和String的两个常用构造函数。
BigDecimal aDouble =new BigDecimal(1.22);
System.out.println("construct with a double value: " + aDouble);
BigDecimal aString = new BigDecimal("1.22");
System.out.println("construct with a String value: " + aString);
输出结果如下:
construct with a double value:1.2199999999999999733546474089962430298328399658203125
construct with a String value: 1.22
(1)参数类型为double的构造方法的结果有一定的不可预知性。
(2)String 构造方法是完全可预知的:写入 newBigDecimal(“0.1”) 将创建一个 BigDecimal,它正好等于预期的 0.1。因此,比较而言,通常建议优先使用String构造方法。
(3)当double必须用作BigDecimal的源时,请使用static valueOf(double)方法。
valueOf源码:
public static BigDecimal valueOf(double val) {
return new BigDecimal(Double.toString(val));
}
2.测试加法操作。
BigDecimal a =new BigDecimal("1.22");
System.out.println("construct with a String value: " + a);
BigDecimal b =new BigDecimal("2.22");
a.add(b);
System.out.println("a plus b is : " + a);
输出结果:a plus b is : 1.22
因为BigDecimal是不可变的(immutable),在进行每一步运算时,都会产生一个新的对象,所以a.add(b);虽然做了加法操作,但是a并没有保存加操作后的值,正确的用法应该是a=a.add(b);
3.测试除法操作。
BigDecimal total1 = new BigDecimal(200).setScale(3, BigDecimal.ROUND_HALF_UP);
//表示这个total1的初始值为200.000
BigDecimal total2 = new BigDecimal(10).setScale(3, BigDecimal.ROUND_HALF_UP);
//表示这个total2的初始值为10.000
total1.divide(total2);
会报错:
Non-terminating decimal expansion; no exact representable decimal result
正确的方法:
total1.divide(total2,3,BigDecimal.ROUND_HALF_UP);
这样才不会报错,你必须为它保留小数位。
总结:
- 商业计算使用BigDecimal。
- 尽量使用参数类型为String的构造函数。
- BigDecimal是不可变的(immutable)的,在进行每一步运算时,都会产生一个新的对象,所以在做加减乘除运算时千万要保存操作后的值。
- 我们往往容易忽略JDK底层的一些实现细节,导致出现错误,需要多加注意。
参考:
http://oracle-9i.iteye.com/blog/1103316
http://blog.csdn.net/jackiehff/article/details/8582449