整型数值精度问题产生的原因
当整型数值进行计算时,其结果超过了它的最大长度或最小长度时(结果溢出),就会出现精度问题
BigInteger类的解决方式
首先,BigInter可以表示任意精度的整数,是因为它使用了数组的形式
- 它会将数据通过byte[]来间接表示底层的二进制,因此只要数组足够长,就能够表示足够大精度的整数,如下
byte[] num1 = { 1 }; // 二进制值:00000001 00000010byte[] num2 = { 1, 2 }; // 二进制值:00000001 00000010byte[] num3 = { 1, 2, 3 }; // 二进制值:00000001 00000010byte[] num4 = { 1, 2, 3, 4, 5 };/* num1, num2, num3 初始化BigInteger后表示的二进制分别为num1: 00000001num2: 00000001 00000010num3: 00000001 00000010 00000011num4: 00000001 00000010 00000011 00000100 00000101注意:初始化参数虽然是byte[],但BigInteger最终会以int[]方式存储,内部参数为mag*/// 十进制值:1 内部mag结果:{ 1 }BigInteger bigNum1 = new BigInteger(num1);// 十进制值:258 内部mag结果:{ 258 }BigInteger bigNum2 = new BigInteger(num2);// 十进制值:66051 内部mag结果:{ 66051 }BigInteger bigNum3 = new BigInteger(num3);// 十进制值:2^32 + 33752069 内部mag结果:{ 1, 33752069 }BigInteger bigNum4 = new BigInteger(num4);
- 它会将数据通过byte[]来间接表示底层的二进制,因此只要数组足够长,就能够表示足够大精度的整数,如下
初始化BigInteger对象源码
// 通过byte[]初始化一个BigIntegerpublic 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();}}// BigInteger内部将byte[]转换成int[]记录到mag中private static int[] stripLeadingZeroBytes(byte a[]) {int byteLength = a.length;int keep;// Find first nonzero bytefor (keep = 0; keep < byteLength && a[keep] == 0; keep++);// Allocate new array and copy relevant part of input arrayint intLength = ((byteLength - keep) + 3) >>> 2;int[] result = new int[intLength];int b = byteLength - 1;for (int i = intLength-1; i >= 0; i--) {result[i] = a[b--] & 0xff;int bytesRemaining = b - keep + 1;int bytesToTransfer = Math.min(3, bytesRemaining);for (int j=8; j <= (bytesToTransfer << 3); j += 8)result[i] |= ((a[b--] & 0xff) << j);}return result;}
进行计算时,是以模拟十进制的方式进行计算的
