原碼、反碼和補碼
原碼,反碼,補碼的產生過程,就是爲了解決,計算機做減法和引入符號位(正號和負號)的問題。
原碼
*原碼:*是最簡單的機器數表示法。用最高位表示符號位,‘1’表示負號,‘0’表示正號。其他位存放該數的二進制的絕對值。
反碼
反碼:正數的反碼還是等於原碼;負數的反碼就是他的原碼除符號位外,按位取反。
補碼
補碼:正數的補碼等於他的原碼 負數的補碼等於反碼+1。 (這只是一種算補碼的方式)
移碼
計算機加減流程及原理
計算機只有加法器 -> 正數和負數的加減運算 ->轉化爲補碼進行加法運算 ->補碼運算的原理在於取負數的同餘數進行加法運算
補碼運算規則
[原碼] + [原碼] -> [補碼]+[補碼] = [補碼] -> [原碼](結果)
位運算核心知識點
- 位運算操作的是整數
- 計算機中,整數以機器數補碼的形式存儲
- 位運算操作的是整數的二進制補碼
位運算
-
位運算只可以處理整數類型(byte、short、int、long)
-
位運算操作的是整數的二進制補碼
-
位運算對byte和short進行移位操作時,在移位之前,會被轉換成int類型,得到的結果也是int類型
位運算規則
位運算符 | 說明 |
---|---|
& |
且 |
| |
或 |
^ |
異或 |
~ |
按位取反 |
<< |
左移運算符,符號位不變,右側低位補0,左側高位捨棄。向左移動指定位數,一般情況下每移動一位都會乘以2(除符號位之外,最高位不爲1的情況下,高位爲1時,超過了位數限制) |
>> |
右移運算符,符號位不變,右側低位捨棄,左側高位正數補0,負數補1。向右移動指定位數,一般情況下每移動一位都是除以2(低位爲1時,會丟失精度) |
>>> |
按位右移補零操作符,無論正負,右側低位捨棄,左側高位插入0 |
位運算符操作的都是補碼,尤其是負數移位操作,應該深刻認識操作的是負數的二進制補碼!!!
JAVA基本類型的默認值和取值範圍
默認值 | 存儲需求(字節) | 取值範圍 | 示例 | |
---|---|---|---|---|
byte | 0 | 1 | -27—27-1 | byte b=10; |
short | 0 | 2 | -215—215-1 | short s=10; |
int | 0 | 4 | -231—231-1 | int i=10; |
long | 0 | 8 | -263—263-1 | long o=10L; |
float | 0.0f | 4 | IEEE754 | float f=10.0F |
double | 0.0d | 8 | IEEE754 | double d=10.0; |
boolean | false | 1 | true\false | boolean flag=true; |
char | ‘ \u0000′ | 2 | 0—2^16-1 | char c=’c’ ; |
int類型和byte數組的相互轉化
/**
* int到byte[]
* @param i
* @return
*/
public static byte[] intToByteArray(int i) {
byte[] result = new byte[4];
// 由高位到低位
result[0] = (byte) ((i >> 24) & 0xFF);
result[1] = (byte) ((i >> 16) & 0xFF);
result[2] = (byte) ((i >> 8) & 0xFF);
result[3] = (byte) (i & 0xFF);
return result;
}
/**
* byte[]轉int
* @param bytes
* @return
*/
public static int byteArrayToInt(byte[] bytes) {
int value = 0;
// 由高位到低位
for (int i = 0; i < 4; i++) {
int shift = (4 - 1 - i) * 8;
value += (bytes[i] & 0x000000FF) << shift;// 往高位遊
}
return value;
}
public static void main(String[] args) {
byte[] b = intToByteArray(128);
System.out.println(Arrays.toString(b));
int i = byteArrayToInt(b);
System.out.println(i);
}
位運算代碼
public static void testBitOperation() {
//數值在機器中以補碼的形式存儲,位運算規則操作的是數值的二進制補碼
int positive = 2; //0... 0000 0010(原碼) 0... 0000 0010(反碼) 0... 0000 0010(補碼)
int negative = -2; //1... 0000 0010(原碼) 1... 1111 1101(反碼) 1... 1111 1110(補碼)
System.out.println("positive:" + positive);
System.out.println("negative:" + negative);
System.out.println("&:" + (positive & negative));//0... 0000 0010(補碼) 0... 0000 0010(反碼) 0... 0000 0010(原碼)
System.out.println("|:" + (positive | negative));//1... 1111 1110(補碼) 1... 1111 1101(反碼) 1... 0000 0010(原碼)
System.out.println("~positive:" + ~positive);//1... 1111 1101(補碼) 1... 1111 1100(反碼) 1... 0000 0011(原碼)
System.out.println("~negative:" + ~negative);//0... 0000 0001(補碼) 0... 0000 0001(反碼) 0... 0000 0001(原碼)
System.out.println("^:" + (positive ^ negative));//1... 1111 1100(補碼) 1... 1111 1011(反碼) 1... 0000 0100(原碼)
System.out.println("positive << 3:" + (positive << 3));//0... 0001 0000(補碼) 0... 0001 0000(反碼) 0... 0001 0000(原碼)
System.out.println("negative << 3:" + (negative << 3));//1... 1111 0000(補碼) 1... 1110 1111(反碼) 1... 0001 0000(原碼)
System.out.println("positive >> 3:" + (positive >> 3));//0... 0000 0000(補碼) 0... 0000 0000(反碼) 0... 0000 0000(原碼)
System.out.println("negative >> 3:" + (negative >> 3));//1... 1111 1111(補碼) 1... 1111 1110(反碼) 1... 0000 0001(原碼)
System.out.println("positive >>> 3:" + (positive >>> 3));//0... 0000 0000(補碼) 0... 0000 0000(反碼) 0... 0000 0000(原碼)
System.out.println("negative >>> 3:" + (negative >>> 3));//0001 1111 1111 1111 1111 1111 1111 1111(補碼\反碼\原碼)
System.out.println("negative >>> 3:" + Integer.parseInt("00011111111111111111111111111111", 2));
}
/**output**/
positive:2
negative:-2
&:2
|:-2
~positive:-3
~negative:1
^:-4
positive << 3:16
negative << 3:-16
positive >> 3:0
negative >> 3:-1
positive >>> 3:0
negative >>> 3:536870911
negative >>> 3:536870911
float類型和double類型
符號位 | 階碼 | 尾數 | 長度 | |
---|---|---|---|---|
float | 1 | 8 | 23 | 32 |
double | 1 | 11 | 52 | 64 |
float和double計算方式
float和double取值範圍和精度問題
-
float和double的取值範圍是由指數的位數來決定的
-
float的指數範圍爲-27~27-1(即-128127),而double的指數範圍爲-2^102^10-1(即-1024~1023)
-
float的範圍爲-2^128 ~ +2^128(-3.40E+38 ~ +3.40E+38)
-
double的範圍爲-2^1024 ~ +2^1024(-1.79E+308 ~ +1.79E+308)
-
float和double的精度是由尾數的位數來決定的
-
float:2^23 = 8388608,一共七位,這意味着最多能有7位有效數字,即float的精度爲6~7位有效數字;
-
double:2^52 = 4503599627370496,一共16位,同理,double的精度爲15~16位。