一、BigDecimal
熟悉浮点记数的朋友知道,用二进制表示十进制小数是存在误差的,在涉及到金钱等其他对小数精度要求高的场景下Java提供了BigDecimal类,以满足需要。
先看构造函数:
public static void main(String[] args) { BigDecimal aNum = new BigDecimal(0.11D); // double BigDecimal bNum = new BigDecimal("1.015"); // String BigDecimal cNum = new BigDecimal("1.15".toCharArray()); // char[] BigDecimal dNum = new BigDecimal(100L);// int or long System.out.println(aNum); System.out.println(bNum); System.out.println(cNum); System.out.println(dNum); System.out.println(aNum.setScale(2, BigDecimal.ROUND_HALF_UP)); }
可以看到一共可满足四大类初始化的方法,即整数、浮点数、字符串、和字符数组。运行后得到如下输出:
0.11000000000000000055511151231257827021181583404541015625 1.015 1.15 100 0.11
输出中浮点并不能精确初始化小数,要得到预想的输出,即0.11,可以在使用时设置精度。如代码最后一行
BigDecimal setScale(int newScale, int roundingMode)
此函数不仅可用于输出格式化,更多的是在加减乘除运算后,设定结果的精度。另外如果想精确初始化小数,建议采用入参为字符串的构造函数。讲到这里,再介绍以下几种常见的近似方式:
1、BigDecimal.ROUND_DOWN 向下取整,例如:1.119 ->1.11;
2、BigDecimal.ROUND_UP 向上取整,例如:1.111 -> 1.12;
3、BigDecimal.ROUND_HALF_DOWN 和 BigDecimal.ROUND_HALF_UP,二者都是以0.5为分界点向上或向下取整近似,ROUND_HALF_DOWN在近似值为0.5时取整为0,ROUND_HALF_UP则取整为1。
另外想说,以0.115D测试区别时,BigDecimal.ROUND_HALF_DOWN 和 BigDecimal.ROUND_HALF_UP两个,近似结果都是0.12,原因是浮点在二进制转化时的误差问题,将0.115D打出来实际是:0.11500000000000000499600361081320443190634250640869140625,按2位近似后面部分实际上是大于0.005的,所以Up和Down都选择了向上进位。要比较这2个区别可以使用参数为String的构造函数得到精确小数。
JDK中自带了加减乘除的方法:
public BigDecimal add(BigDecimal value); public BigDecimal subtract(BigDecimal value); public BigDecimal multiply(BigDecimal value); public BigDecimal divide(BigDecimal value);
二、BigInteger
之所以关注到BigInteger是因为在做某个阶乘运算时,发现java中基本类型long在算到18!就GG了,于是发现了这个神奇的东西。
先谈初始化,奇怪的是没有直接提供参数为整数的构造函数而是以静态函数BigInteger.valueOf()的形式,在String类型的参数初始化时又是以构造函数的形式,不支持valueOf(),具体如下:
BigInteger eNum = BigInteger.valueOf(11L); BigInteger fNum = new BigInteger("123414");
同样提供基本运算方法:
1、 add(b);//相加 2、subtract(); //相减 3、multiply(); //相乘 4、divide(); //相除取整 5、remainder(); //取余 6.pow(); //求幂次方 7.gcd(); //最大公约数 8.abs(); //绝对值 9.negate(); //取反数
BigInteger如何存储大数字?
阅读源码可以发现,输入值val最终是被存在mag中的,而mag初始定义为:final int[] mag,也就说BigInteger存储数字的基本方向就是用int[]数组分位存储。而int最大值为2147483647,数组下标默认为int型,即mag数组最大能有2147483647个元素,每个元素最大表示2147483647,因此BigIntrger能表示的最大值为[-2^(2147483647*32-1) ,2^(2147483647*32-1)-1]。
public BigInteger(byte[] val) { if (val.length == 0) throw new NumberFormatException("Zero length BigInteger"); if (val[0] < 0) { mag = makePositive(val); signum = -1; } else { mag = stripLeadingZeroBytes(val); signum = (mag.length == 0 ? 0 : 1); } if (mag.length >= MAX_MAG_LENGTH) { checkRange(); } }
另外,为了提高效率在-16~16范围内的BigInteger返回的是同一个实例,这个似乎和Integer在-128到 127设置静态缓存是一样的做法。
public static BigInteger valueOf(long val) { // If -MAX_CONSTANT < val < MAX_CONSTANT, return stashed constant if (val == 0) return ZERO; if (val > 0 && val <= MAX_CONSTANT) return posConst[(int) val]; else if (val < 0 && val >= -MAX_CONSTANT) return negConst[(int) -val]; return new BigInteger(val); }
参考:
1、https://blog.csdn.net/gjb724332682/article/details/51488765