標籤:
現在什麼事都動不動大資料了。連個int也level up成了BigInteger。在一些情境似乎還不得不使用它。
於是有人賤賤地問:“這個天到底有多大呢?”
不,應該是“這個BigInteger到底有多大呢?”
讓我們來看看BigInteger的內部結構吧。
在BigInteger中,一個大int其實是由一個int數組實現的,即mag。還有一個int數值signum,用來作為正負標記。
public class BigInteger extends Number implements Comparable<BigInteger> { /** * The signum of this BigInteger: -1 for negative, 0 for zero, or * 1 for positive. Note that the BigInteger zero <i>must</i> have * a signum of 0. This is necessary to ensures that there is exactly one * representation for each BigInteger value. * * @serial */ final int signum; /** * The magnitude of this BigInteger, in <i>big-endian</i> 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 ({@code 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. */ final int[] mag;
那麼,如何將一個範圍大於int範圍的數存在BigInteger的mag數組中呢?
BigInteger有很多重載的構造器,我們挑選其中一個來說明就明白了:
/** * Constructs a BigInteger with the specified value, which may not be zero. */ private BigInteger(long val) { if (val < 0) { val = -val; signum = -1; } else { signum = 1; } int highWord = (int)(val >>> 32); if (highWord==0) { mag = new int[1]; mag[0] = (int)val; } else { mag = new int[2]; mag[0] = highWord; mag[1] = (int)val; } }
我們可以看到,對於long長度為8位元組,正好是兩個int的大小。在上面的構造器中,先通過向右移位32位,取得long的高32位的數,如果為0,則表示long的實際值並沒有超過int的範圍,於是mag數組只申請一個int的大小,儲存long的低32位即可;如果不為0,則說明long的實際值已經超出int的範圍,這時候,mag申請兩個int大小,將高位32位存在mag[0],低位32位存在mag[1]。
也就是位元高的存在前面,位元低的存在後面。
好吧,回到原先的問題,BigInteger有多大?
mag既然是數組,那麼它的長度收到下標範圍的影響,即mag的個數不會超過int的最大值,即2的31次方-1,即2147483647。那麼每個int是32位。那麼mag所能夠大表的位元是2147483647*32。
所以,BigInteger的範圍應該是[-22147483647*32-1 ,22147483647*32-1 -1]
HappyBKs強迫症——BigInteger有多大?