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