BIgInteger类和BigDecimal类的理解
第一部分:
这两个类位于java.math包内,要使用它们必须在类前面引用该包:import java.math.BigInteger;和import java.math.BigDecimal;
BigInteger和BigDecimal分别表示不可变的任意精度的整数和不可变的有符号的任意精度的十进制数(浮点数)。主要用于高精度计算中。这两个类使得java中的大数,高精度运算变得很简单。
下面从几个方面对BigInteger和BigDecima做一个简单的比较:
一.常量
BigInteger:ONE,ZERO,TEN分别代表1,0,10.
其定义类似于:public static final BigInteger ONE = valueOf(1);
BigDecimal:除了以上三个常量外还有8个关于舍入的常量,这里不再赘述,可以去查看API的帮助手册.
顺便说一句,BigDecimal由于舍入模式的存在,使得这个类用起来比BigInteger要复杂.这里不再赘述,具体可以查看API的帮助手册,但是平时对起复杂特性用的不多,所以用的时候查阅API也是可行的.
二.声明赋值
BigInteger:BigInteger bi = new BigInteger("100");或:BigInteger bi = BigInteger.valueOf(100);
数组定义与基本类型类似.
BigDecimal:BigDecimal bd = new BigDecimal(100);或:BigDecimal bd = BigDecimal.valueOf(100);
BigDecimal的构造函数比BigInteger多一些,感觉用起来更方便些,比如这样定义就是错误的:BigInteger bi = new BigInteger(100);
顺便说一下,java.util包中的Scanner类实现了nextBigInteger()和nextBigDecimal()方法,可以用来读入控制台输入的BigInteger和BigDecimal.给个例子:
- Scanner sc = new Scanner(System.in);
- while(sc.hasNext()){
- BigInteger bi;
- //BigDecimal bd;
- bi = sc.nextBigInteger();//读入BigInteger
- // bd = sc.nextBigDecimal();//读入BigDecimal
- System.out.println(bi.toString());
- //System.out.println(bd.toString());
- }
三.相关函数
主要介绍一下四则运算等函数:
用两个例子来说明比较直观一些:
BigInteger:
- package Factorial;
- import java.math.BigInteger;
- import java.util.Random;
- /**
- * 测试BigInteger类的一些函数
- * @author LY 2011-10-27
- * */
- public class BigIntegerDemo {
- public static void main(String[] arguments){
- System.out.println("构造两个BigInteger对象: ");
- //BigInteger(int numBits, Random rnd)
- //构造一个随机生成的 BigInteger,它是在 0 到 (2^numBits - 1)(包括)范围内均匀分布的值
- BigInteger bi1 = new BigInteger(55,new Random());
- System.out.println("bi1 = " + bi1);
- //BigInteger(byte[] val)
- //将包含 BigInteger 的二进制补码表示形式的 byte 数组转换为 BigInteger。
- BigInteger bi2 = new BigInteger(new byte[]{3,2,3});
- System.out.println("bi2 = " + bi2);
- //加
- System.out.println("bi1 + bi2 = " + bi1.add(bi2));
- //减
- System.out.println("bi1 - bi2 = " + bi1.subtract(bi2));
- //乘
- System.out.println("bi1 * bi2 = " + bi1.multiply(bi2));
- //指数运算
- System.out.println("bi1的2次方 = " + bi1.pow(2));
- //整数商
- System.out.println("bi1/bi2的整数商: " + bi1.divide(bi2));
- //余数
- System.out.println("bi1/bi2的余数: " + bi1.remainder(bi2));
- //整数商+余数
- System.out.println("bi1 / bi2 = " + bi1.divideAndRemainder(bi2)[0] +
- "--" + bi1.divideAndRemainder(bi2)[1]);
- System.out.println("bi1 + bi2 = " + bi1.add(bi2));
- //比较大小,也可以用max()和min()
- if(bi1.compareTo(bi2) > 0)
- System.out.println("bd1 is greater than bd2");
- else if(bi1.compareTo(bi2) == 0)
- System.out.println("bd1 is equal to bd2");
- else if(bi1.compareTo(bi2) < 0)
- System.out.println("bd1 is lower than bd2");
- //返回相反数
- BigInteger bi3 = bi1.negate();
- System.out.println("bi1的相反数: " + bi3);
- //返回绝对值
- System.out.println("bi1的绝对值: " + bi3.abs());
- }
- }
运行结果:
- 构造两个BigInteger对象:
- bi1 = 8893838204110884
- bi2 = 197123
- bi1 + bi2 = 8893838204308007
- bi1 - bi2 = 8893838203913761
- bi1 * bi2 = 1753180068308949786732
- bi1的2次方 = 79100358000902314326836967261456
- bi1/bi2的整数商: 45118216565
- bi1/bi2的余数: 168389
- bi1 / bi2 = 45118216565--168389
- bi1 + bi2 = 8893838204308007
- bd1 is greater than bd2
- bi1的相反数: -8893838204110884
- bi1的绝对值: 8893838204110884
BigDecimal:
- package Factorial;
- import java.math.BigDecimal;;
- /**
- * 测试BigDecimal类的一些函数
- * @author LY 2011-10-27
- * */
- public class BigDecimalDemo {
- public static void main(String[] arguments){
- System.out.println("构造两个BigDecimal对象: ");
- //用char[]数组创建BigDecimal对象,第二个参数为位移offset,
- //第三个参数指定长度
- BigDecimal bd1 = new BigDecimal("3464656776868432998434".toCharArray(),2,15);
- System.out.println("bd1 = " + bd1);
- //用double类型创建BigDecimal对象
- BigDecimal bd2 = new BigDecimal(134258767575867.0F);
- System.out.println("bd2 = " + bd2);
- //加
- System.out.println("bd1 + bd2 = " + bd1.add(bd2));
- //减
- System.out.println("bd1 - bd2 = " + bd1.subtract(bd2));
- //乘
- System.out.println("bd1 * bd2 = " + bd1.multiply(bd2));
- //指数运算
- System.out.println("bd1的2次方 = " + bd1.pow(2));
- //取商的整数部分
- System.out.println("bd1/bd2的整数商: " + bd1.divideToIntegralValue(bd2));
- //返回余数计算为:this.subtract(this.divideToIntegralValue(divisor).multiply(divisor))
- //System.out.println(bd1.subtract(bd1.divideToIntegralValue(bd2).multiply(bd2)));
- System.out.println("bd1/bd2的余数: " + bd1.remainder(bd2));
- //取商和余,即bd1.divideToIntegralValue(bd2)与bd1.remainder(bd2)
- System.out.println("bd1 / bd2 = " + bd1.divideAndRemainder(bd2)[0] +
- "--" + bd1.divideAndRemainder(bd2)[1]);
- //比较大小,也可以用max()和min()
- if(bd1.compareTo(bd2) > 0)
- System.out.println("bd1 is greater than bd2");
- else if(bd1.compareTo(bd2) == 0)
- System.out.println("bd1 is equal to bd2");
- else if(bd1.compareTo(bd2) < 0)
- System.out.println("bd1 is lower than bd2");
- //末位数据精度
- System.out.println("bd1的末位数据精度: " + bd1.ulp());
- }
- }
运行结果:
- 构造两个BigDecimal对象:
- bd1 = 646567768684329
- bd2 = 134258765070336
- bd1 + bd2 = 780826533754665
- bd1 - bd2 = 512309003613993
- bd1 * bd2 = 86807390157840676971865964544
- bd1的2次方 = 418049879501431972683650180241
- bd1/bd2的整数商: 4
- bd1/bd2的余数: 109532708402985
- bd1 / bd2 = 4--109532708402985
- bd1 is greater than bd2
- bd1的末位数据精度: 1
本文对BigInteger和BigDecimal类进行了比较浅显的介绍及比较,如对这两个类有兴趣,可以查阅API或研读其源码.
---恢复内容结束---
这两个类位于java.math包内,要使用它们必须在类前面引用该包:import java.math.BigInteger;和import java.math.BigDecimal;
BigInteger和BigDecimal分别表示不可变的任意精度的整数和不可变的有符号的任意精度的十进制数(浮点数)。主要用于高精度计算中。这两个类使得java中的大数,高精度运算变得很简单。
下面从几个方面对BigInteger和BigDecima做一个简单的比较:
一.常量
BigInteger:ONE,ZERO,TEN分别代表1,0,10.
其定义类似于:public static final BigInteger ONE = valueOf(1);
BigDecimal:除了以上三个常量外还有8个关于舍入的常量,这里不再赘述,可以去查看API的帮助手册.
顺便说一句,BigDecimal由于舍入模式的存在,使得这个类用起来比BigInteger要复杂.这里不再赘述,具体可以查看API的帮助手册,但是平时对起复杂特性用的不多,所以用的时候查阅API也是可行的.
二.声明赋值
BigInteger:BigInteger bi = new BigInteger("100");或:BigInteger bi = BigInteger.valueOf(100);
数组定义与基本类型类似.
BigDecimal:BigDecimal bd = new BigDecimal(100);或:BigDecimal bd = BigDecimal.valueOf(100);
BigDecimal的构造函数比BigInteger多一些,感觉用起来更方便些,比如这样定义就是错误的:BigInteger bi = new BigInteger(100);
顺便说一下,java.util包中的Scanner类实现了nextBigInteger()和nextBigDecimal()方法,可以用来读入控制台输入的BigInteger和BigDecimal.给个例子:
- Scanner sc = new Scanner(System.in);
- while(sc.hasNext()){
- BigInteger bi;
- //BigDecimal bd;
- bi = sc.nextBigInteger();//读入BigInteger
- // bd = sc.nextBigDecimal();//读入BigDecimal
- System.out.println(bi.toString());
- //System.out.println(bd.toString());
- }
三.相关函数
主要介绍一下四则运算等函数:
用两个例子来说明比较直观一些:
BigInteger:
- package Factorial;
- import java.math.BigInteger;
- import java.util.Random;
- /**
- * 测试BigInteger类的一些函数
- * @author LY 2011-10-27
- * */
- public class BigIntegerDemo {
- public static void main(String[] arguments){
- System.out.println("构造两个BigInteger对象: ");
- //BigInteger(int numBits, Random rnd)
- //构造一个随机生成的 BigInteger,它是在 0 到 (2^numBits - 1)(包括)范围内均匀分布的值
- BigInteger bi1 = new BigInteger(55,new Random());
- System.out.println("bi1 = " + bi1);
- //BigInteger(byte[] val)
- //将包含 BigInteger 的二进制补码表示形式的 byte 数组转换为 BigInteger。
- BigInteger bi2 = new BigInteger(new byte[]{3,2,3});
- System.out.println("bi2 = " + bi2);
- //加
- System.out.println("bi1 + bi2 = " + bi1.add(bi2));
- //减
- System.out.println("bi1 - bi2 = " + bi1.subtract(bi2));
- //乘
- System.out.println("bi1 * bi2 = " + bi1.multiply(bi2));
- //指数运算
- System.out.println("bi1的2次方 = " + bi1.pow(2));
- //整数商
- System.out.println("bi1/bi2的整数商: " + bi1.divide(bi2));
- //余数
- System.out.println("bi1/bi2的余数: " + bi1.remainder(bi2));
- //整数商+余数
- System.out.println("bi1 / bi2 = " + bi1.divideAndRemainder(bi2)[0] +
- "--" + bi1.divideAndRemainder(bi2)[1]);
- System.out.println("bi1 + bi2 = " + bi1.add(bi2));
- //比较大小,也可以用max()和min()
- if(bi1.compareTo(bi2) > 0)
- System.out.println("bd1 is greater than bd2");
- else if(bi1.compareTo(bi2) == 0)
- System.out.println("bd1 is equal to bd2");
- else if(bi1.compareTo(bi2) < 0)
- System.out.println("bd1 is lower than bd2");
- //返回相反数
- BigInteger bi3 = bi1.negate();
- System.out.println("bi1的相反数: " + bi3);
- //返回绝对值
- System.out.println("bi1的绝对值: " + bi3.abs());
- }
- }
运行结果:
- 构造两个BigInteger对象:
- bi1 = 8893838204110884
- bi2 = 197123
- bi1 + bi2 = 8893838204308007
- bi1 - bi2 = 8893838203913761
- bi1 * bi2 = 1753180068308949786732
- bi1的2次方 = 79100358000902314326836967261456
- bi1/bi2的整数商: 45118216565
- bi1/bi2的余数: 168389
- bi1 / bi2 = 45118216565--168389
- bi1 + bi2 = 8893838204308007
- bd1 is greater than bd2
- bi1的相反数: -8893838204110884
- bi1的绝对值: 8893838204110884
BigDecimal:
- package Factorial;
- import java.math.BigDecimal;;
- /**
- * 测试BigDecimal类的一些函数
- * @author LY 2011-10-27
- * */
- public class BigDecimalDemo {
- public static void main(String[] arguments){
- System.out.println("构造两个BigDecimal对象: ");
- //用char[]数组创建BigDecimal对象,第二个参数为位移offset,
- //第三个参数指定长度
- BigDecimal bd1 = new BigDecimal("3464656776868432998434".toCharArray(),2,15);
- System.out.println("bd1 = " + bd1);
- //用double类型创建BigDecimal对象
- BigDecimal bd2 = new BigDecimal(134258767575867.0F);
- System.out.println("bd2 = " + bd2);
- //加
- System.out.println("bd1 + bd2 = " + bd1.add(bd2));
- //减
- System.out.println("bd1 - bd2 = " + bd1.subtract(bd2));
- //乘
- System.out.println("bd1 * bd2 = " + bd1.multiply(bd2));
- //指数运算
- System.out.println("bd1的2次方 = " + bd1.pow(2));
- //取商的整数部分
- System.out.println("bd1/bd2的整数商: " + bd1.divideToIntegralValue(bd2));
- //返回余数计算为:this.subtract(this.divideToIntegralValue(divisor).multiply(divisor))
- //System.out.println(bd1.subtract(bd1.divideToIntegralValue(bd2).multiply(bd2)));
- System.out.println("bd1/bd2的余数: " + bd1.remainder(bd2));
- //取商和余,即bd1.divideToIntegralValue(bd2)与bd1.remainder(bd2)
- System.out.println("bd1 / bd2 = " + bd1.divideAndRemainder(bd2)[0] +
- "--" + bd1.divideAndRemainder(bd2)[1]);
- //比较大小,也可以用max()和min()
- if(bd1.compareTo(bd2) > 0)
- System.out.println("bd1 is greater than bd2");
- else if(bd1.compareTo(bd2) == 0)
- System.out.println("bd1 is equal to bd2");
- else if(bd1.compareTo(bd2) < 0)
- System.out.println("bd1 is lower than bd2");
- //末位数据精度
- System.out.println("bd1的末位数据精度: " + bd1.ulp());
- }
- }
运行结果:
- 构造两个BigDecimal对象:
- bd1 = 646567768684329
- bd2 = 134258765070336
- bd1 + bd2 = 780826533754665
- bd1 - bd2 = 512309003613993
- bd1 * bd2 = 86807390157840676971865964544
- bd1的2次方 = 418049879501431972683650180241
- bd1/bd2的整数商: 4
- bd1/bd2的余数: 109532708402985
- bd1 / bd2 = 4--109532708402985
- bd1 is greater than bd2
- bd1的末位数据精度: 1
本文对BigInteger和BigDecimal类进行了比较浅显的介绍及比较,如对这两个类有兴趣,可以查阅API或研读其源码.
第二部分:
BigDecimal 由任意精度的整数非标度值 和 32 位的整数标度 (scale) 组成。如果为零或正数,则标度是小数点后的位数。如果为负数,则将该数的非标度值乘以 10 的负 scale 次幂。因此,BigDecimal 表示的数值是 (unscaledValue × 10-scale)。
可以处理任意长度的浮点数运算。
BigDecimal add(BigDecimal val) //BigDecimal 加法
BigDecimal subtract (BigDecimal val) //BigDecimal 减法
BigDecimal multiply (BigDecimal val) //BigDecimal 乘法
BigDecimal divide (BigDecimal val,RoundingMode mode) 除法
具体使用 计算:
加: a.add(b);
减: a.subtract(b);
乘: a.multiply(b);
除: a.divide(b,2);//2为精度取值
除法细解:
//注意以下相除会抛出异常,原因: 通过BigDecimal的divide方法进行除法时当不整除,出现无限循环小数时,就会抛异常
//BigDecimal divideBg = a.divide(b);
//解决方法是:设置精确度;就是给divide设置精确的小数点
divide(xxxxx,2, BigDecimal.ROUND_HALF_EVEN)
//其中的第二个参数表示的是:保留小数点之后多少位
BigDecimal不整除抛出的异常,请设置精确度!
Exception in thread "main" java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result.
at java.math.BigDecimal.divide(BigDecimal.java:1278)
at main.Main.main(Main.java:41)
下面我们来看看除法的详细说明:
divide(BigDecimal divisor, int scale, introundingMode)
BigDecimal的setScale方法
BigDecimal.setScale()
方法用于格式化小数点
表示保留一位小数,默认用四舍五入方式
setScale(1)
直接删除多余的小数位,如2.35会变成2.3 setScale(1,BigDecimal.ROUND_DOWN)
进位处理,2.35变成2.4 setScale(1,BigDecimal.ROUND_UP)
四舍五入,2.35变成2.4 setScale(1,BigDecimal.ROUND_HALF_UP)
四舍五入,2.35变成2.3,如果是5则向下舍setScaler(1,BigDecimal.ROUND_HALF_DOWN)
注意点一
scale指的是你小数点后的位数。
scale()就是BigDecimal类中的方法。如
BigDecimal b = new BigDecimal("123.456");
b.scale()返回的就是3
注意点二roundingMode是小数的保留模式。它们都是BigDecimal中的常量字段,
有很多种,如
BigDecimal.ROUND_HALF_UP表示的就是4舍5入
注意点三
divide(BigDecimal divisor, int scale, introundingMode)的意思是说:
我用一个BigDecimal对象除以divisor后的结果,并且要求这个结果保留有scale个小数位,roundingMode表示的就是保留模式是什么,是四舍五入啊还是其它的
BigDecimal aa = new BigDecimal(135.95 );
BigDecimal bb=new BigDecimal("100" );
BigDecimal result=aa.multiply(bb); //做加法
3.java中 BigDecimal类型的可以转换到double类型:
用 变量.doubleValue();函数 即可将 BigDecimal 类型数据 转化为 double类型!
4.java BigDecimal比较大小
可以通过BigDecimal的compareTo方法来进行比较。
返回的结果是int类型,-1表示小于,0是等于,1是大于。
看下面这个例子:
BigDecimal a = new BigDecimal("1.00");
BigDecmial b = new BigDecimal(1);
想比较一下a和b的大小,一般都会用equals
System.out.println(a.equals(b));
但是输出结果是:false
原因是:BigDecimal比较时,不仅比较值,而且还比较精度?
if(a.compareTo(b)==0) 结果是true
比较大小可以用 a.compareTo(b)
返回值 -1 小于 0 等于 1 大于
5.BigDecimal取其中最大、最小值、绝对值、相反数:
a.max (b) //比较取最大值
a.min(b) //比较取最小值
a.abs()//取最绝对值
a.negate()//取相反数
6.下面是注意 :
BigDecimal枚举常量用法摘要 :
CEILING
向正无限大方向舍入的舍入模式。
DOWN
向零方向舍入的舍入模式。
FLOOR
向负无限大方向舍入的舍入模式。
HALF_DOWN
向最接近数字方向舍入的舍入模式,如果与两个相邻数字的距离相等,则向下舍入。
HALF_EVEN
向最接近数字方向舍入的舍入模式,如果与两个相邻数字的距离相等,则向相邻的偶数舍入。
HALF_UP
向最接近数字方向舍入的舍入模式,如果与两个相邻数字的距离相等,则向上舍入。
UNNECESSARY
用于断言请求的操作具有精确结果的舍入模式,因此不需要舍入。
UP
远离零方向舍入的舍入模式。
7.关于BigDecimal格式化
public String formatValue(Object value){
String content = null;
if (value == null) {
content = "";
} else {
if(value instanceof BigDecimal){
//conver to fortmat String
NumberFormat nf = NumberFormat.getInstance();
nf.setMinimumFractionDigits(2);
nf.setMaximumFractionDigits(2);
content = nf.format(value);
}else{
content = String.valueOf(value);
}
}
return content;
}
使用这样一个方法可以达到格式化的效果,其中value instanceof BigDecimal,表示的是字符类型是BigDecimal类型的时候执行,这里的NumberFormat就表示字符类型,下面的两句代码就表示小数点后面的精确位数。
这里还要提到NumberFormat的其他两个类型:
getCurrencyInstance(): 返回当前默认 环境的货币格式
CurrencyInstance(): 返回指定语言 环境的数字格式,一般是百分比格式
8.在《Effective Java》这本书中也提到这个原则,float和double只能用来做科学计算或者是工程计算,在商业计算中我们要用java.math.BigDecimal。
我们如果需要精确计算,非要用String来够造BigDecimal不可!
下面的这个工具类是是转载别人的,可以通过个工具类实现小数的精确计算。
1import java.math.BigDecimal;
2/** *//**
3* 由于Java的简单类型不能够精确的对浮点数进行运算,这个工具类提供精
4* 确的浮点数运算,包括加减乘除和四舍五入。
5*/
6public class Arith{
7 //默认除法运算精度
8 private static final int DEF_DIV_SCALE = 10;
9 //这个类不能实例化
10 private Arith(){
11 }
12
13 /** *//**
14 * 提供精确的加法运算。
15 * @param v1 被加数
16 * @param v2 加数
17 * @return 两个参数的和
18 */
19 public static double add(double v1,double v2){
20 BigDecimal b1 = new BigDecimal(Double.toString(v1));
21 BigDecimal b2 = new BigDecimal(Double.toString(v2));
22 return b1.add(b2).doubleValue();
23 }
24 /** *//**
25 * 提供精确的减法运算。
26 * @param v1 被减数
27 * @param v2 减数
28 * @return 两个参数的差
29 */
30 public static double sub(double v1,double v2){
31 BigDecimal b1 = new BigDecimal(Double.toString(v1));
32 BigDecimal b2 = new BigDecimal(Double.toString(v2));
33 return b1.subtract(b2).doubleValue();
34 }
35 /** *//**
36 * 提供精确的乘法运算。
37 * @param v1 被乘数
38 * @param v2 乘数
39 * @return 两个参数的积
40 */
41 public static double mul(double v1,double v2){
42 BigDecimal b1 = new BigDecimal(Double.toString(v1));
43 BigDecimal b2 = new BigDecimal(Double.toString(v2));
44 return b1.multiply(b2).doubleValue();
45 }
46
47 /** *//**
48 * 提供(相对)精确的除法运算,当发生除不尽的情况时,精确到
49 * 小数点以后10位,以后的数字四舍五入。
50 * @param v1 被除数
51 * @param v2 除数
52 * @return 两个参数的商
53 */
54 public static double div(double v1,double v2){
55 return div(v1,v2,DEF_DIV_SCALE);
56 }
57
58 /** *//**
59 * 提供(相对)精确的除法运算。当发生除不尽的情况时,由scale参数指
60 * 定精度,以后的数字四舍五入。
61 * @param v1 被除数
62 * @param v2 除数
63 * @param scale 表示表示需要精确到小数点以后几位。
64 * @return 两个参数的商
65 */
66 public static double div(double v1,double v2,int scale){
67 if(scale<0){
68 throw new IllegalArgumentException(
69 "The scale must be a positive integer or zero");
70 }
71 BigDecimal b1 = new BigDecimal(Double.toString(v1));
72 BigDecimal b2 = new BigDecimal(Double.toString(v2));
73 return b1.divid(b2,scale,BigDecimal.ROUND_HALF_UP).doubleValue();
74 }
75
76 /** *//**
77 * 提供精确的小数位四舍五入处理。
78 * @param v 需要四舍五入的数字
79 * @param scale 小数点后保留几位
80 * @return 四舍五入后的结果
81 */
82 public static double round(double v,int scale){
83 if(scale<0){
84 throw new IllegalArgumentException(
85 "The scale must be a positive integer or zero");
86 }
87 BigDecimal b = new BigDecimal(Double.toString(v));
88 BigDecimal one = new BigDecimal("1");
89 return b.divid(one,scale,BigDecimal.ROUND_HALF_UP).doubleValue();
90 }
91 }