解析java.math.BigInteger類——構造函數


     最早由於做作業,結識了java的BigInrger類。讀着讀着,越來越覺得有趣。后來作業做完,也不忍丟下它,索性把全部代碼研究一遍。

     開始的時候,一個上午時間最多讀懂2個方法。但是還是有滋有味的堅持了下來。下面開始一點點剖開它“隱藏”的秘密。

     首先要想搞懂兩個問題:BigIngeter類的目的——實現高精度數的存儲和計算。基礎的實現機理——用int型(32位)數組存儲數據。(在代碼的注釋中有詳細說明)

/////////////////////////////////////////////////////////////

BigInteger類中的屬性:{

int signum;    符號位,負數是為-1,零時為0,正數是為1

int[] mag;     The magnitude of this BigInteger,大數的值
//其他輔助變量暫時先不看

}

首先來分析下構造函數 (構造五部曲:1.檢查是否符合標准 2.去零 3.mag賦值 4.去mag中零 5.符號位賦值)

1. 使用byte(8位)型數組構造BigInteger:

/////////////////////////////////////////////////////////////////////

 public BigInteger(byte[] val) {
  if (val.length == 0)
     throw new NumberFormatException("Zero length BigInteger"); //傳入數組長度為零,報錯

  if (val[0] < 0) {
        mag = makePositive(val);
     signum = -1;                 //如果數組第一個值為負數,則將數組變正存入mag,signum賦-1
 } else {
     mag = stripLeadingZeroBytes(val);  //如果非負,則可直接去掉前面無效零,再賦給mag
     signum = (mag.length == 0 ? 0 : 1);

}

}

下面看一下具體調用的函數

///////////////////////////////////////////////////////////////////////////

private static int[] stripLeadingZeroBytes(byte a[]) {
 int byteLength = a.length;
 int keep;

 // Find first nonzero byte
 for (keep=0; keep<a.length && a[keep]==0; keep++)  //找到第一個有效位,並用keep記錄下
     ;

 // Allocate new array and copy relevant part of input array
        int intLength = ((byteLength - keep) + 3)/4;   //計算int[]的長度,byte[1/2/3/4]對應int[1]

 int[] result = new int[intLength];
        int b = byteLength - 1;
        for (int i = intLength-1; i >= 0; i--) {
            result[i] = a[b--] & 0xff;           //向int[]賦值,&0xff的作用是消除對int前24位的影響

(計算機中使用補碼存儲數據,如果直接將一個第一位為“1”的byte值賦給int,則前24為將為“1”)

            int bytesRemaining = b - keep + 1;
            int bytesToTransfer = Math.min(3, bytesRemaining);
            for (int j=8; j <= 8*bytesToTransfer; j += 8)
                result[i] |= ((a[b--] & 0xff) << j);     //進行移位,每次移動8位,再進行或運算
        }
        return result;
    }

 //////////////////////////////////////////////////////////////

  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++) //找出非符號位(此處我看了很久才看懂)。若a[]=-1,即計算機中二進制為“11111111”,在int型中全為“1”的前幾位被認為是符號位。要想轉換成正的int值,只需要后幾位即可。
   ;
 
        
for (k=keep; k<byteLength && a[k]==0; k++)        //由於傳入參數數組第一個值必為負(由構造函數可得),所以不必考慮去零,變量k的作用只是判斷需要“額外”位
   ;
 
int extraByte = (k==byteLength) ? 1 : 0;         //如果除符號位以外的全部為“0”,則需要“額外”1位來存儲數據
        int intLength = ((byteLength - keep + extraByte) + 3)/4;
int result[] = new int[intLength];
 
        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);
            if (numBytesToTransfer < 0)
                numBytesToTransfer = 0;
            for (int j=8; j <= 8*numBytesToTransfer; j += 8)
                result[i] |= ((a[b--] & 0xff) << j);
 
            // Mask indicates which bits must be complemented
            int mask = -1 >>> (8*(3-numBytesToTransfer));  //將負值變為正值,即由原碼轉反碼
            result[i] = ~result[i] & mask;
        }
 
// Add one to one's complement to generate two's complement
for (int i=result.length-1; i>=0; i--) {
            result[i] = (int)((result[i] & LONG_MASK) + 1);  //long LONG_MASK = 0xffffffffL;為了進行位運算而不考慮int符號問題
   if (result[i] != 0)     //(這個地方也把我蒙騙了好久)突然恍悟,其實就是+1后不為零,即不需要進位,就break退出吧!
                break;
        }
 
return result;
    }
 
2.  使用int(32位)型數組構造BigInteger:
/////////////////////////////////////////////////////////////
private BigInteger(int[] val) {
if (val.length == 0)
   throw new NumberFormatException("Zero length BigInteger");
 
if (val[0] < 0) {
            mag = makePositive(val);
   signum = -1;
} else {
   mag = trustedStripLeadingZeroInts(val);
   signum = (mag.length == 0 ? 0 : 1);
}
    }
 
與byte[]構造原理相同,並且更為簡單,不重述。有一點說明,這里使用trustedStripLeadingZeroInts可信賴的去零方法,與StripLeadingZeroInts的區別在於,對於可信賴的去零方法,如果沒有無效零,則直接返回原數組,不進行復制。
 
 
轉於:http://blog.sina.com.cn/s/blog_6c58b3bf01013wer.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM