1. BigDecimal简介:
1) 用Java的基础类型来表示数据还是有一定的局限性的:
i. 对于整型最明显的就是存在界限问题,由于使用有限位二进制数来表示整型,必定存在上下限,不能表示更大范围的数了;
ii. 对于浮点型就不用说了,根本无法精确表示,例如一个字面值0.1也无法在底层用二进制精确表示!
2) BigDecimal——精确实数:
i. Java提供BigDecimal类来表示精确实数;
ii. 它底层使用字符串来保存数字的,而字符串的位数不受限制,这就首先突破了整型界限的问题;
iii. 其次,同样是由于用字符串来保存数字的,对于浮点数其小数部分可以精确到最低位;
2. 构造:
1) 首推用字符串来构造:毕竟本身底层即使用字符串保存的
i. BigDecimal(String val);
ii. BigDecimal(char[] val);
iii. BigDecimal(char[] val, int offset, int len);
!!分别用String和字符数组来构造,例如:BigDecimal num = new BigDecimal("0.123");
2) 当然也可以用基本类型来构造:
i. BigDecimal(int | long | double val); // 只支持这三种类型
ii. 也可以用其静态工具方法来构造:static BigDecimal BigDecimal.valueOf(long | double val); // 只支持long和double
!!但是double版本的最好不要用!!因为double本身就是不精确的,转换成BigDecimal同样是不精确的!!(转换的方法就是取其字符串表示形式)
3. 转换成基本类型:
1) 当然也允许将BigDecimal类型转换成相应的基本类型;
2) 对于整型:type typeValue[Exact](); // type支持byte、short、int、long
i. 这里转换的时候问题又两个,一个是BigDecimal表示的是实数,可能有小数点,另一个时转换成相应的整型时可能会溢出;
ii. 没有Exact的版本遇到上面两个问题没有异常,直接截断处理(这可能会导致后续程序的错误);
iii. Exact的版本遇到上面两个问题时会抛出异常!
!!通常使用第二个版本;
4. 算术运算:
1) 二元运算:BigDecimal op(BigDecimal val); // this op val
i. 加:add
ii. 减:subtract
iii. 乘:multiply
!!除法非常特殊,最后详解
2) 指数运算:BigDecimal pow(int n); // this ^ n
3) 一元运算:
i. 绝对值:BigDecimal abs();
ii. 取反(加一个负号):BigDecimal negate();
iii. 信号采样:int signum(); // 负数返回-1,正数1,0返回0
iv. 自加(自己加自己,不是加1):BigDecimal plus();
4) 除法为什么特殊:
i. BigDecimal表示精确实数,因此其进行运算之后得到的结果也希望是精确实数,精确实数经过上述的所有运算之后得到的结果必然也是精确的,但是除法就不一定了;
ii. 最简单的就是1 / 3得到的就是无限循环的0.333...,对于无限循环小数BigDecimal再精确也无法表示了,因为不可能存无限个3啊!!
iii. 考虑到这个问题,BigDecimal的除法divide就需要考虑精度问题了!
iv. 因此除法通常含有控制精度的参数;
5) 除法:
i. 完整版:BigDecimal divide(BigDecimal divisor, int scale, RoundingMode roundingMode);
a. divisor是除数,scale是精度(小数点后保留几位),roundingMode是取舍方式;
b. 取舍方式:都是BigDecimal中定义的静态常量,常用的有
HALF_UP:四舍五入
CEILING:取上限
FLOOR:取下限
UNNECESSARY:没必要取舍,这就意味着得到的结果一定是精确的、不会有无限循环的,但是一旦有就会抛出异常!!
ii. BigDecimal divide(BigDecimal divisor, int roundingMode); // 精度使用默认值,取舍方式自己决定
iii. BigDecimal divide(BigDecimal divisor); // 精度默认,取舍方式默认是UNNECESSARY,因此小心抛出异常哦!!
6) 既然有除法,必然有模除咯!
i. 首先要知道整除(即结果只取除法结果的整数部分):BigDecimal divideToIntegralValue(BigDecimal divisor); // 定义为a \ b
ii. 接着就是模除:BigDecimal remainder(BigDecimal divisor); // 理论上就是a % b
!!但是BigDecimal表示的是实数,因此两个操作数都可能有小数点,而这里的模除是广义模除,其运算方法就是 a - (a \ b) × b,因此结果很可能也有小数点,并且也可能是负数!
7) 还有同时得到除数和余数的方法:BigDecimal[] divideAndRemainder(BigDecimal divisor); // 把上面两个方法分别放在[0]和[1]中一块儿返回(先\结果,后%结果)