屬性簡介
負數 | -1 |
0 | 0 |
正數 | 1 |
字節序為大端模式,大端模式就是低地址存儲高位
對於BigInteger 他的數據打開就是這么一種形式
[ 101....32位....1] [ 110....32個....1] ....N個..... [ 0110....32個....1]
它的真值的計算方法與其他的二進制序列一樣的
二進制為 0111 1110 的十進制為126 相信誰都會計算,BigInteger也是如此的
尤其是對於BigInteger字符串參數的構造形式
千萬不要以為就是把字符的編碼或者字符轉換成數字切段存放到int數組中
他存放的都是轉換后的真值
下面會詳細介紹
|
使用字節數組構造
- 如果是一個負數,會先得到真值的絕對值
- 如果有前導零,還會去掉所有的前導零
原碼/反碼/補碼
原碼 |
符號位+數值位
符號位為0 表示正數,符號位為1 表示負數
數值位就是真值的絕對值
又被稱為帶符號的絕對值表示
|
反碼 | 正數的反碼為其原碼 負數的反碼為其原碼的除符號位外,逐位取反 |
補碼 | 正數的補碼為其原碼 負數的補碼為其反碼+1 |
補碼計算步驟
第一步求原碼: 先寫出來她的原碼--->符號位+數值位(絕對值) |
第二步求反碼:
如果是正數 反碼與原碼一樣
如果是負數 反碼為原碼取反(除符號位外,逐位翻轉)
|
第三步求補碼: 如果是正數 補碼與原碼一樣 如果是負數 補碼為反碼 + 1 |
第四步擴充: 如果不足數據類型的寬度,將需要填充到指定寬度 符號位擴充,也就是正數補0 負數補1 |
總結 不管什么形式,第一位始終都是符號位,0 表示正數, 1表示負數 正數原碼/反碼/補碼 全都一樣,知道一種就直接得到另外的形式 負數如果知道補碼,想要得到他的原碼,只需要對補碼再一次的求補碼即可 |
示例1
示例2
使用String構造
算法基礎
BigInteger內部使用int數組表示 普通數值使用每個數值位上的數字進行表示 |
一個BigInteger有多個int 一個普通數值有多個數字位 |
每個int能夠表示的指定進制的最大值--intRadix 中保存的數據
其實 就是 BigInteger 的基於每個int作為一個元素的進制基數
|
digitsPerInt 表示不同基數(進制)下一個int 能夠表示的數字的長度 ,這個位數其實就是按照多長進行分割組裝
intRadix 就是基數
bitsPerDigit 是用來推算需要多少個int的,也就是int數組的長度
|
構造方法源碼解析
public BigInteger(String val, int radix) {
//定義了兩個變量一個光標,光標記錄着應該要處理的數據索引下標
//另一個numDigits 用來保存需要處理的數字位數 也就是有效長度,比如去掉前導零后的
int cursor = 0, numDigits;
final int len = val.length();//傳遞進來的字符數組的長度
//如果給定的基數,不在合法范圍內,那么拋出異常,不會默認處理
if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX)
throw new NumberFormatException("Radix out of range");
//如果字符串長度為0 也是一種非法的參數
if (len == 0)
throw new NumberFormatException("Zero length BigInteger");
// Check for at most one leading sign
int sign = 1;
int index1 = val.lastIndexOf('-');
int index2 = val.lastIndexOf('+');
//符號- + 只能出現一個,而且還必須是第一個位置,否則都不合法
//根據最后一個的索引與0 進行比較,可以簡便的判斷符號位是否合法
if (index1 >= 0) {
if (index1 != 0 || index2 >= 0) {
throw new NumberFormatException("Illegal embedded sign character");
}
sign = -1;
cursor = 1;
} else if (index2 >= 0) {
if (index2 != 0) {
throw new NumberFormatException("Illegal embedded sign character");
}
cursor = 1;
}
//經過前面的判斷,如果有符號位的話,光標的值更新為1 也就是后續不處理符號位
//如果此時光標的值等於字符長度,說明沒有有效數字了,將會拋出異常
if (cursor == len)
throw new NumberFormatException("Zero length BigInteger");
// Skip leading zeros and compute number of digits in magnitude
//如果有前導0 ,將會去掉這些,光標的位置也會跟着一起移動
while (cursor < len &&
Character.digit(val.charAt(cursor), radix) == 0) {
cursor++;
}
//跳過了所有的0之后就不再有有效數據了,說明他就是個0
//哪怕他原來設置的負數的0 將會變為0 的標記
if (cursor == len) {
signum = 0;
mag = ZERO.mag;
return;
}
//記錄實際需要處理的數據長度以及對符號位使用signum進行記錄
numDigits = len - cursor;
signum = sign;
// Pre-allocate array of expected size. May be too large but can
// never be too small. Typically exact.
//根據前面的公式計算實際需要的二進制位數 numDigits需要處理的數字的長度
//bitsPerDigit 里面記錄了每個進制1位數需要的二進制位數,但是放大了1024倍,所以還要除以1024 也就是右移10
//真正的值可能是小數個,除以1024之后變成了取整了,然后再加上一,百分百夠用,需要的比特位數保存到numBits
long numBits = ((numDigits * bitsPerDigit[radix]) >>> 10) + 1;
if (numBits + 31 >= (1L << 32)) {
reportOverflow();
}
//numWords 記錄的是實際需要的int類型數據的個數,也就是數組的長度
//右移5位就是除以32 就是計算數組的長度,除法會取整,防止1個不足32位的時候,就會變成0了所以numBits加上31 之后再除以32
int numWords = (int) (numBits + 31) >>> 5;
//此時創建真正的保存數據的int數組了
int[] magnitude = new int[numWords];
// Process first (potentially short) digit group
//numDigits 需要處理的數字的個數
//digitsPerInt 保存的是每一個int能夠保存的指定數制下的字符長度
//如果有余數,說明有一個不足最大長度的位數
//如果沒有余數,那么每一組都是剛好能夠保存的最大長度
int firstGroupLen = numDigits % digitsPerInt[radix];
if (firstGroupLen == 0)
firstGroupLen = digitsPerInt[radix];
//第一組數據存放到數組的最后一個
String group = val.substring(cursor, cursor += firstGroupLen);
magnitude[numWords - 1] = Integer.parseInt(group, radix);
if (magnitude[numWords - 1] < 0)
throw new NumberFormatException("Illegal digit");
// Process remaining digit groups
int superRadix = intRadix[radix];
int groupVal = 0;
while (cursor < len) {
group = val.substring(cursor, cursor += digitsPerInt[radix]);
groupVal = Integer.parseInt(group, radix);
if (groupVal < 0)
throw new NumberFormatException("Illegal digit");
// 這個方法是用來累計計算的,方法內部寫的很復雜
//其實邏輯很簡單,比如一個數字序列1234,求他表示的值是多少
// ( ( (1*10)+2 )*10+3 )*10 +4 = 1234
//這個方法就是用來計算的,只不過每一個位置是一個int 低32位當做數值 高32位當做進位
destructiveMulAdd(magnitude, superRadix, groupVal);
}
// Required for cases where the array was overallocated.
mag = trustedStripLeadingZeroInts(magnitude);
if (mag.length >= MAX_MAG_LENGTH) {
checkRange();
}
}
構造方法運行步驟
字符串構造方法計算示例
其他構造方法
方法簡介
基礎方法
獲取符號位 signum() |
常用數學函數 negate() 取負 abs() 絕對值
pow(int) 求冪
gcd(BigInteger) 最大公約數
min(BigInteger) 最小值
max(BigInteger) 最大值
|
四則運算與取整求余
add(BigInteger) 加法
subtract(BigInteger) 減法
multiply(BigInteger) 乘法
divide(BigInteger) 除法(取整)
remainder(BigInteger) 求余
divideAndRemainder(BigInteger) 取整和求余 返回的是一個數組
|
獲取基本類型的值
不同於基本數值類型的包裝類,此處並不是直接強轉的
如果太大intValue 和 longValue 將分別返回低的32位和64位
longValue 和 doubleValue可能會被轉換為無窮
intValue()
longValue()
floatValue()
doubleValue()
|
數值類型的准確值
longValueExact()
intValueExact()
shortValueExact()
byteValueExact()
所謂准確就是不會舍入或者轉換,因為他們會進行數據長度的校驗
否則將會拋出異常
比如
|
位操作相關
and(BigInteger) 與
or(BigInteger) 或
not() 非
xor(BigInteger) 異或
andNot(BigInteger) 返回其值為 (this & ~val) 的 BigInteger 等效於 and(val.not())
shiftLeft(int) 左移
shiftRight(int) 右移
|
取模與求余對比
計算過程相同
對於整型數a,b來說,取模運算或者求余運算的方法都是:
求模運算和求余運算在第一步不同:
取余運算在取c的值時,向0 方向舍入;
而取模運算在計算c的值時,向負無窮方向舍入;
因此,求模時結果的符號與b一致,求余時結果的符號與a一致
如果a,b都是正整數的話,求模與求余沒有區別
|
mod(BigInteger)
返回其值為 (this mod m) 的 BigInteger,取模不同於 remainder
BigInteger modPow(BigInteger exponent,BigInteger m)
BigInteger modInverse(BigInteger m)
|
bitCount與bitLength
public int bitCount() 返回此 BigInteger 的二進制補碼表示形式中與符號不同的位的數量 特別注意這個方法的含義 不是二進制補碼表示形式的 1 位的數量,而是與符號不同的 |
bitLength 最小的二進制補碼表示形式的位數,不包括 符號位 對於正 BigInteger,這等於常規二進制表示形式中的位數 就是去掉符號位占用的長度 |
valueOf(long)
equals(Object)
toString hashCode CompareTo
public String toString(int radix) 轉換為指定基數
toString()
|
hashCode() |
compareTo(BigInteger)
小於、等於或大於 時,返回 -1,0,或 1
|
素數相關
是否素數
public boolean isProbablePrime(int certainty)
如果此 BigInteger 可能為素數,則返回 true,如果它一定為合數,則返回 false
如果 certainty <= 0,則返回 true
參數:
certainty - 調用方允許的不確定性的度量
如果該調用返回 true,則此 BigInteger 是素數的概率超出 ( 1 - 1/(2的certainty次方) )
此方法的執行時間與此參數的值是成比例的
返回:
如果此 BigInteger 可能為素數,則返回 true,如果它一定為合數,則返回 false
|
public static BigInteger probablePrime(int bitLength,
Random rnd)
返回有可能是素數的、具有指定長度的正 BigInteger此方法返回的 BigInteger 是合數的概率不超出 2的-100次方
參數:
bitLength - 返回的 BigInteger 的 bitLength。
rnd - 隨機比特源,用這些隨機比特選擇用來進行質數測試的候選數
|
nextProbablePrime
public BigInteger nextProbablePrime()
返回大於此 BigInteger 的可能為素數的第一個整數
此方法返回的數是合數的概率不超出 2的-100次方
|
特殊的"位操作"
testBit(int) 計算 (this & (1<<n)) != 0
setBit(int) 計算 this | (1<<n)
clearBit(int) 計算 this & ~(1<<n)
flipBit(int) 計算 this ^ (1<<n)
|
getLowestSetBit()
返回此 BigInteger 最右端(最低位)1 比特位的索引
也就是從最右邊開始數找到的第一個1
此字節的右端開始到本字節中最右端 1 之間的 0 比特的位數
如果此 BigInteger 不包含1位,則返回 -1
計算 this==0? -1 : log2(this & -this)
|
toByteArray
public byte[] toByteArray() |
BigInteger 內部使用int數組進行數據保存 一個int包含4個byte BigInteger可以使用byte數組構造 也自然能夠分解成byte數組進行保存 |