BigInteger简析
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BigInteger简析相关的知识,希望对你有一定的参考价值。
简介
big-endian和little-endian
地址 0 1 2 3
数据 05 06 07 08
在LITTLE-ENDIAN的情况下存放为:
数据 08 07 06 05
BigInteger
先看一下JDK对BigInteger类的介绍:
Immutable arbitrary-precision integers. All operations behave as if BigIntegers were represented in two‘s-complement notation (like Java‘s primitive integer types).
BigInteger provides analogues to all of Java‘s primitive integer operators, and all relevant methods from java.lang.Math. Additionally, BigInteger provides operations for modular arithmetic, GCD calculation, primality testing, prime generation, bit manipulation, and a few other miscellaneous operations.
上面这段话的意思是:
BigInteger是不可变的任意精度的整数。所有操作中,都以二进制补码形式表示 BigInteger(如 Java 的基本整数类型)。BigInteger 提供所有 Java 的基本整数操作符的对应物,并提供 java.lang.Math 的所有相关方法。另外,BigInteger 还提供以下运算:模算术、GCD 计算、质数测试、素数生成、位操作以及一些其他操作。
下面看看BigInteger有哪些重点的属性,主要的有下面三个:
(1)final int signum
signum属性是为了区分:正负数和0的标志位,JDK注释里面已经说的很明白了,-1代表负数,0代表0,1代表整数:
The signum of this BigInteger: -1 for negative, 0 for zero, or 1 for positive. Note that the BigInteger zero must have a signum of 0. This is necessary to ensures that there is exactly one representation for each BigInteger value.
(2)final int[] mag
mag是magnitude的缩写形式,mag表示的是正数的原码字节数组。mag数组是存储BigInteger数值大小的,采用big-endian的顺序,也就是高位字节存入低地址,低位字节存入高地址,依次排列的方式。JDK原文注释如下:
The magnitude of this BigInteger, in big-endian order: the zeroth element of this array is the most-significant int of the magnitude. The magnitude must be "minimal" in that the most-significant int (mag[0]) must be non-zero. This is necessary to ensure that there is exactly one representation for each BigInteger value. Note that this implies that the BigInteger zero has a zero-length mag array.
(3)final static long LONG_MASK = 0xffffffffL;
This mask is used to obtain the value of an int as if it were unsigned。
构造函数
BigInteger(byte[] val)
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); } }一、如果第一个字节是负数,则这个byte[] val就是负数的补码。因此通过补码的逆运算(补码的补码)可以得到负数的绝对值,再将符号位设置为-,则得到这个补码所代表的负数。下面是源码,其中红色的为我的注解。
private static int[] makePositive(byte a[]) { int keep, k; int byteLength = a.length; // Find first non-sign (0xff) byte of input for (keep=0; keep<byteLength && a[keep]==-1; keep++)<span style="color:#ff0000;">//keep表示第一个非符号位也就是-1的字节索引,keep索引开始的字节是有效字节</span> ; <span style="color:#ff0000;">//k用于判断,从非符号位开始后面的字节是否全是0,如果是,则表示这个值是补码所能表示的最小值。固定二进制位数下,补码表示的数值范围是负数最小值的绝对值比正数最大值大1,因此如果要表示负数最小值的绝对值,就要多加1位二进制位,在这里就表现为多加一个byte。</span> /* Allocate output array. If all non-sign bytes are 0x00, we must * allocate space for one extra output byte. */ for (k=keep; k<byteLength && a[k]==0; k++) ; int extraByte = (k==byteLength) ? 1 : 0; int intLength = ((byteLength - keep + extraByte) + 3)/4;<span style="color:#ff0000;">//result数组的长度取决于有效字节的个数和extraByte</span> int result[] = new int[intLength];<span style="color:#ff0000;">//要返回的结果数组</span> /* Copy one‘s complement of input into output, leaving extra * byte (if it exists) == 0x00 */ int b = byteLength - 1; for (int i = intLength-1; i >= 0; i--) { result[i] = a[b--] & 0xff; int numBytesToTransfer = Math.min(3, b-keep+1)<span style="color:#ff0000;">;//numBytesToTransfer表示接下来有几个字节需要填充到result数组里,一个int4个字节,所以最大取3</span> if (numBytesToTransfer < 0) numBytesToTransfer = 0; for (int j=8; j <= 8*numBytesToTransfer; j += 8) result[i] |= ((a[b--] & 0xff) << j);<span style="color:#ff0000;">//每个字节占8位,所以每次递加8位</span> // Mask indicates which bits must be complemented<span style="color:#ff0000;">//mask用于标记哪几个字节需要取反(one‘s complement)</span> int mask = -1 >>> (8*(3-numBytesToTransfer)); result[i] = ~result[i] & mask; } // Add one to one‘s complement to generate two‘s complement<span style="color:#ff0000;">//补码取反后,result数组最大索引处的值加1,得到原码(也就是这个负数补码所对应的整数)</span> for (int i=result.length-1; i>=0; i--) { result[i] = (int)((result[i] & LONG_MASK) + 1); if (result[i] != 0)<span style="color:#ff0000;">//result[i]此时已经是原码了,如果原码全是0,补码也必定全身0。补码全0取反后是全1,加1后要进位,因此result[i+1]要加1</span> break; } return result; }
/** * Returns a copy of the input array stripped of any leading zero bytes. */ 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; }
BigInteger(int signum, byte[] magnitude)
public BigInteger(int signum, byte[] magnitude) { this.mag = stripLeadingZeroBytes(magnitude); if (signum < -1 || signum > 1) throw(new NumberFormatException("Invalid signum value")); if (this.mag.length==0) { this.signum = 0; } else { if (signum == 0) throw(new NumberFormatException("signum-magnitude mismatch")); this.signum = signum; } }
BigInteger(String val)
BigInteger(String val, int radix)
BigInteger(int numBits, Random rnd)
BigInteger(int bitLength, int certainty, Random rnd)
注意事项
java.math.BigInteger系列教程(八)BigInteger如何存储大数据的?
public static BigInteger valueOf(long val)
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); }
/** * Initialize static constant array when class is loaded. */ private final static int MAX_CONSTANT = 16; private static BigInteger posConst[] = new BigInteger[MAX_CONSTANT+1]; private static BigInteger negConst[] = new BigInteger[MAX_CONSTANT+1]; static { for (int i = 1; i <= MAX_CONSTANT; i++) { int[] magnitude = new int[1]; magnitude[0] = i; posConst[i] = new BigInteger(magnitude, 1); negConst[i] = new BigInteger(magnitude, -1); } }
System.out.println(BigInteger.valueOf(16) == BigInteger.valueOf(16));//true System.out.println(BigInteger.valueOf(17) == BigInteger.valueOf(17));//false System.out.println(BigInteger.valueOf(-16) == BigInteger.valueOf(-16));//true System.out.println(BigInteger.valueOf(-17) == BigInteger.valueOf(-17));//false
基本运算示例
public static void main(String[] args) { BigInteger b1 = BigInteger.valueOf(20l); BigInteger b2 = BigInteger.valueOf(10l); System.out.println(b1.add(b2).toString());//加 30 System.out.println(b1.subtract(b2).toString());//减 10 System.out.println(b1.multiply(b2).toString());//乘 200 System.out.println(b1.divide(b2).toString());//除 2 System.out.println(b1.remainder(b2).toString());//取余 0 }
以上是关于BigInteger简析的主要内容,如果未能解决你的问题,请参考以下文章