BigDecimal,BigInteger 學習以及簡單示例

最近的項目中用到了BigDecimal,之前並沒有深入學習使用過,只是大概知道可以用於精確的運算,而float和double是不精確的。

BigDecimal的實現中用到了BigIntegr,因此這裏先學習下BigInteger。

BigInteger

int和long都有長度限制,如果需要計算的整數大小超過long的範圍,那麼可以用到BigInteger。

BigInteger繼承自抽象類Number。

// 符號,-1-負數,0-0,1-正數
final int signum;
//以大尾數順序表示的這個大整數的大小:這個數組的第0個元素是該大小中最重要的整數。
//大小必須“最小”,因爲最重要的int(@code mag[0])必須爲非零。
//這對於確保每個biginteger值只有一個表示是必要的。注意,這意味着biginteger zero有一個零長度的mag數組。
// mag表示的是正數的原碼字節數組。mag數組是存儲BigInteger數值大小的,採用big-endian的順序,也就是高位字節存入低地址,低位字節存入高地址.
// http://www.mamicode.com/info-detail-1360414.html
final int[] mag;
// 冗餘字段
private int bitCount;
// 冗餘字段
private int bitLength;
// 冗餘字段
private int lowestSetBit;
// 冗餘字段
private int firstNonzeroIntNum;
// 用於獲取int值
final static long LONG_MASK = 0xffffffffL;
// 數組最大長度
private static final int MAX_MAG_LENGTH = Integer.MAX_VALUE / Integer.SIZE + 1; // (1 << 26)
// PRIME_SEARCH_BIT_LENGTH_LIMIT 大於這個長度的大數會導致BitSieve.singleSearch方法溢出
private static final  int PRIME_SEARCH_BIT_LENGTH_LIMIT = 500000000;
// 兩個大數的mag[] 長度都大於這個值,將會使用Karatsuba multiplication
private static final int KARATSUBA_THRESHOLD = 80;
// 如果兩個數mag長度都大於KARATSUBA_THRESHOLD,且至少一個的長度大於這個限度,將會使用3-way Toom-Cook multiplication
private static final int TOOM_COOK_THRESHOLD = 240;
// 如果大數的數組長度大於該限制,將會使用Karatsuba squaring
private static final int KARATSUBA_SQUARE_THRESHOLD = 128;
// 如果大數的數組長度大於該限制,將會使用Toom-Cook squaring
private static final int TOOM_COOK_SQUARE_THRESHOLD = 216;
// 下面幾個參數作用類似,暫時不記錄,等到以後需要時再細看
static final int BURNIKEL_ZIEGLER_THRESHOLD = 80;
static final int BURNIKEL_ZIEGLER_OFFSET = 40;
private static final int SCHOENHAGE_BASE_CONVERSION_THRESHOLD = 20;
private static final int MULTIPLY_SQUARE_THRESHOLD = 20;
private static final int MONTGOMERY_INTRINSIC_THRESHOLD = 512;

構造函數

// 該部分註釋來自於 http://www.mamicode.com/info-detail-1360414.html
public BigInteger(byte[] val) {
        if (val.length == 0)
            throw new NumberFormatException("Zero length BigInteger");

        // 如果第一個字節是負數,則這個byte[] val就是負數的補碼。因此通過補碼的逆運算(補碼的補碼)可以得到負數的絕對值,再將符號位設置爲-,則得到這個補碼所代表的負數。
        // 如果參數字節數組以-1開頭,不管幾個,只要-1是連續的,那麼這些-1都看成是符號-,這些-1的下一個字節纔是有效字節。如果不以-1開頭而是其他負數,則有效字節從索引0開始。
        if (val[0] < 0) {
            mag = makePositive(val);
            signum = -1;
        } else {
            // 如果第一個字節是整數,則採用stripLeadingZeroBytes方法,將每個字節的二進制補碼按順序連接起來後去掉開頭的0後返回。
            mag = stripLeadingZeroBytes(val);
            signum = (mag.length == 0 ? 0 : 1);
        }
        if (mag.length >= MAX_MAG_LENGTH) {
            checkRange();
        }
    }
// 將一個包含大數的二進制補碼的的int數組轉換爲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);
        }
        if (mag.length >= MAX_MAG_LENGTH) {
            checkRange();
        }
    }
// 在上邊兩個構造函數中加上了signum來判斷符號的正負
public BigInteger(int signum, byte[] magnitude);

private BigInteger(int signum, int[] magnitude)
// 把val按照radix進制轉化爲大數,val中可以包含一個可選的-或+,不可以有空格
public BigInteger(String val, int radix)
// 10進制的BigInteger(String val, int radix)方法
public BigInteger(String val)

其他的暫時看不下去了,等待需要用到的時候看吧,令人頭禿。

先看幾個常用的方法:

// 返回一個大整數,其值等於指定的@code long。此“靜態工廠方法”優先於(@code long)構造函數提供,因爲它允許重用常用的大整數。
// 如果值在-16-16之間,那麼返回的BigInteger是同一個對象。
public static BigInteger valueOf(long val)

// 原因,以下代碼在靜態代碼塊中,返回時就是返回這兩個數組對應位置的對象
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);
}

使用BigInteger做加減乘除運算時,分別需要調用實例方法:

BigInteger test1 = BigInteger.valueOf(7);
BigInteger test2 = BigInteger.valueOf(8);
BigInteger testNeg = BigInteger.valueOf(-1);
BigInteger r1 = test1.add(test2);
BigInteger r2 = test1.subtract(test2);
BigInteger r3 = test1.multiply(test2);
BigInteger r4 = test1.divide(test2);

和long相比,BigInteger不會有長度限制,但是計算效率較低。

BigInteger也是不可變類,可以轉換爲基本類型,轉換時會丟失高位信息。

BigDecimal

BigDecimal可以表示一個任意大小且精度完全準確的浮點數。

// 待完善
private final BigInteger intVal;
// 表示小數位數
private final int scale;  
// 小數的位數,如果小數位數未知則爲0,如果非0,保證值時正確的
private transient int precision;

// 用於存儲規範的字符串表示形式
private transient String stringCache;

// intCompact的值,表示有意義的部分只能從intVal中獲得
static final long INFLATED = Long.MIN_VALUE;

private static final BigInteger INFLATED_BIGINT = BigInteger.valueOf(INFLATED);

// 如果此bigdecimal的有效位的絕對值小於或等於@code long.max,則該值可以緊湊地存儲在此字段中並用於計算。
private final transient long intCompact;

// 所有18位十進制字符串都適合一個long;並非所有19位字符串都適合
private static final int MAX_COMPACT_DIGITS = 18;

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章