java 二進制(原碼 反碼 補碼),位運算,移位運算,約瑟夫問題

一.二進制,位運算,移位運算

1.二進制

對於原碼, 反碼, 補碼而言, 須要注意如下幾點:java

(1).Java中沒有無符號數, 換言之, Java中的數都是有符號的;node

(2).二進制的最高位是符號位, 0表示正數, 1表示負數;數組

(3).正數的原碼, 反碼, 補碼都同樣;函數

(4).負數的反碼=它的原碼符號位不變, 其餘位取反;性能

(5).負數的補碼=它的反碼+1;ui

(6).0的反碼, 補碼都是0;this

(7).在計算機運算的時候, 都是以補碼的方式來運算的.spa

2.位運算

Java中有4個位運算, 分別是按位與&, 按位或|, 按位異或^, 按位取反~, 它們的運算規則爲:code


3.移位運算

Java中有3個移位運算符, 分別是算術右移>>, 算術左移<<, 邏輯右移>>>, 它們的運算規則爲:blog


4.簡單的程序實例

複製代碼
public class Demo1 { public static void main(String[] args) { System.out.println(~2); System.out.println(2&3); System.out.println(2|3); System.out.println(~-5); System.out.println(13&7); System.out.println(5|4); System.out.println(-3^3); } }
複製代碼

運行結果:

-3
2
3
4
5
5
-2

複製代碼
public class Demo2 { public static void main(String[] args) { System.out.println(1>>2); System.out.println(-1>>2); System.out.println(1<<2); System.out.println(-1<<2); System.out.println(3>>>2); } }
複製代碼

運行結果:

0
-1
4
-4
0




位(bit)  一位二進制數,又稱比特 

字節(byte)  1B = 8b  內存存儲的最小單元 

字長:同一時間內,計算機能處理的二進制位數 

字長決定了計算機的運算精度,字長越長,計算機的運算精度就越高。所以,高性能的計算機,其字長較長,而性能較差的計算機,其字長相對要短一些。     
其次,字長決定了指令直接尋址的能力。通常機器的字長都是字節的一、二、四、8倍。微機的字長爲8位、16位、32位、64位,如286機爲16位機,386和486是32位機,最新推出的PIII爲64位高檔機。     
字長也影響機器的運算速度,字長越長,運算速度越快。  
字:是計算機中處理數據或信息的基本單位。一個字由若干字節組成,一般將組成一個字的位數叫作該字的字長。 

進制 
一位八進制數字能夠用三位二進數來表示,一位十六進制數能夠用四位二進數來表示,因此二進制和八進制、十六進制間的轉換很是簡單 


如:將(1010111.01101)2轉換成八進制數 

    1010111.01101=001 010 111. 011 010 

               ↓ ↓ ↓ ↓ ↓ 

                 1  2    7     3    2 

因此(1010111.011.1)2=(127.32)8 

  

將(327.5)8轉換爲二進制 

3       2      7.     5 

↓     ↓    ↓    ↓ 

011    010   111.   101 

    因此(327.5)8=(11010111.101)2 

將(110111101.011101)2轉換爲十六進制數 

(110111101.011101)2=0001   1011   1101.   0111   0100 

                      ↓      ↓      ↓       ↓       ↓ 

                       1   B       D        7      4 

因此(110111101.011101)2=(1BD.74)16 

  

將(27.FC)16轉換成二進制數 

  2       7.     F        C     

↓    ↓    ↓     ↓     

0010  0111  1111   1100 

因此(27.FC)16=(100111.111111)2 

 二進制表示 

原碼:每一位表示符號 

反碼:正數同原碼,負數除符號外其它位相反 

補碼:正數同原碼,負數除符號外,反碼+1獲得 

地址總線: 
地址總線寬度決定了CPU能夠訪問的物理地址空間,簡單地說就是CPU到底可以使用多大容量的內存 

8位地址總線:一個8位的二進制數最多能表示2的8次方個數據,從00000000到11111111,十進制爲0-255,這樣,8位地址總線最大能區分的地址是從0到255。咱們說他的尋址能力爲256, 即256字節 

16位地址總線:64K 

20位: 1M 

32位: 4G 

上面是不一樣地址總線,能訪問的物理內存。注意:計算時,如16位地址總線的尋址能力不是16個1組成的二進制數的結果,而是要再加上1,由於前面有個00000000000000000     
即2的16次方, 而16個1組成的二進制數爲2的16次方減1 


其餘: 

十進制轉二進制:  
用2展轉相除至結果爲1  
將餘數和最後的1從下向上倒序寫 就是結果  
例如302  
302/2 = 151 餘0  
151/2 = 75 餘1  
75/2 = 37 餘1  
37/2 = 18 餘1  
18/2 = 9 餘0  
9/2 = 4 餘1  
4/2 = 2 餘0  
2/2 = 1 餘0  
故二進制爲100101110  

二進制轉十進制  
從最後一位開始算,依次列爲第0、一、2...位  
第n位的數(0或1)乘以2的n次方  
獲得的結果相加就是答案  
例如:01101011.轉十進制:  
第0位:1乘2的0次方=1  
1乘2的1次方=2  
0乘2的2次方=0  
1乘2的3次方=8  
0乘2的4次方=0  
1乘2的5次方=32  
1乘2的6次方=64  
0乘2的7次方=0  
而後:1+2+0  
+8+0+32+64+0=107.  
二進制01101011=十進制107.  

1、二進制數轉換成十進制數  
由二進制數轉換成十進制數的基本作法是,把二進制數首先寫成加權係數展開式,而後按十進制加法規則求和。這種作法稱爲"按權相加"法。  

2、十進制數轉換爲二進制數  
十進制數轉換爲二進制數時,因爲整數和小數的轉換方法不一樣,因此先將十進制數的整數部分和小數部分分別轉換後,再加以合併。  
1. 十進制整數轉換爲二進制整數  
十進制整數轉換爲二進制整數採用"除2取餘,逆序排列"法。具體作法是:用2去除十進制整數,能夠獲得一個商和餘數;再用2去除商,又會獲得一個商和餘數,如此進行,直到商爲零時爲止,而後把先獲得的餘數做爲二進制數的低位有效位,後獲得的餘數做爲二進制數的高位有效位,依次排列起來。  

2.十進制小數轉換爲二進制小數  
十進制小數轉換成二進制小數採用"乘2取整,順序排列"法。具體作法是:用2乘十進制小數,能夠獲得積,將積的整數部分取出,再用2乘餘下的小數部分,又獲得一個積,再將積的整數部分取出,如此進行,直到積中的小數部分爲零,或者達到所要求的精度爲止。  
而後把取出的整數部分按順序排列起來,先取的整數做爲二進制小數的高位有效位,後取的整數做爲低位有效位。  
回答者:HackerKinsn - 試用期 一級 2-24 13:31 

1.二進制與十進制的轉換  
(1)二進制轉十進制<BR>方法:"按權展開求和"  
例:  
(1011.01)2 =(1×23+0×22+1×21+1×20+0×2-1+1×2-2)10  
=(8+0+2+1+0+0.25)10  
=(11.25)10  
(2)十進制轉二進制  

· 十進制整數轉二進制數:"除以2取餘,逆序輸出"  
例: (89)10=(1011001)2  
2 89  
2 44 …… 1  
2 22 …… 0  
2 11 …… 0  
2 5 …… 1  
2 2 …… 1  
2 1 …… 0  
0 …… 1  
· 十進制小數轉二進制數:"乘以2取整,順序輸出"  
例:  
(0.625)10= (0.101)2  
0.625  
X 2  
1.25  
X 2  
0.5  
X 2  
1.0  
2.八進制與二進制的轉換  
例:將八進制的37.416轉換成二進制數:  
37 . 4 1 6  
011 111 .100 001 110  
即:(37.416)8 =(11111.10000111)2  
例:將二進制的10110.0011 轉換成八進制:  
0 1 0 1 1 0 . 0 0 1 1 0 0  
2 6 . 1 4  
即:(10110.011)2 =(26.14)8  
3.十六進制與二進制的轉換<BR>例:將十六進制數5DF.9 轉換成二進制:  
5 D F . 9  
0101 1101 1111.1001  
即:(5DF.9)16 =(10111011111.1001)2  

例:將二進制數1100001.111 轉換成十六進制:  
0110 0001 . 1110  
6 1 . E  
即:(1100001.111)2 =(61.E)16






二.約瑟夫問題

約瑟夫問題: 設編號爲1,2,3...n的n我的圍坐一圈, 約定編號爲k(1<=k<=n)的人從1開始報數, 數到m的那我的出列, 它的下一位又從1開始報數, 數到m的那我的又出列, 依次類推, 直到全部人出列爲止, 由此產生一個出隊編號的序列.

複製代碼
public class Demo3 { public static void main(String[] args) { CycleLinkList cycleLinkList=new CycleLinkList(); cycleLinkList.setCycleLinkListLength(10); cycleLinkList.initCycleLinkList(); cycleLinkList.Josephu(4, 6); } } /** * 節點結構 */
class Node { //編號
    private int number; //指向下一個節點的引用
    private Node nextNode=null; //構造函數
    public Node(int number) { this.number=number; } //設置nextNode節點
    public void setNextNode(Node nextNode) { this.nextNode = nextNode; } //獲得nextNode節點
    public Node getNextNode() { return nextNode; } //獲得編號
    public int getNumber() { return number; } } /** * 循環鏈表 */
class CycleLinkList { //鏈表的長度
    private int length=0; //指向鏈表頭結點的引用
    private Node firstNode=null; /** * 設置鏈表的長度 * @param len 鏈表長度 */
    public void setCycleLinkListLength(int len) { this.length=len; } /** * 初始化循環鏈表 */
    public void initCycleLinkList() { //定義一個臨時節點
        Node tempNode=null; for(int i=1;i<=length;i++) { //頭節點
            if(1==i) { Node headNode=new Node(i); this.firstNode=headNode; tempNode=headNode; }else { //尾節點
                if(length==i) { Node node=new Node(i); tempNode.setNextNode(node); tempNode=node; //將尾節點的nextNode引用指向鏈表的頭節點firstNode
 tempNode.setNextNode(firstNode); }else { //其它節 Node node=new Node(i); tempNode.setNextNode(node); tempNode=node; } } } } /** * 打印循環鏈表 */
    public void printCycleLinkList() { Node tempNode=this.firstNode; do { System.out.println(tempNode.getNumber()); tempNode=tempNode.getNextNode(); } while (tempNode!=this.firstNode); } /** * 約瑟夫問題 * @param k 從第k我的開始報數 * @param m 數m下 */
    public void Josephu(int k, int m) { //判斷k的合法性
        if( !(k>=1 && k<=this.length) ) { System.out.println("傳入的k不正確"); System.exit(-1); } //定義一個臨時節點
        Node tempNode=this.firstNode; //先找到第k我的
        for(int i=1;i<k;i++) { tempNode=tempNode.getNextNode(); } //數m下,將數到m的節點從循環鏈表中刪除 //有兩種狀況須要考慮, //第一種:m=1的情形 //第二種:除了第一種的特殊狀況,其餘的只要找到數到m節點的的前一個節點便可,即數m-1下 //第一種情形
        if(1==m) { //從當前節點依次輸出出隊序列
            int len=this.length; while( (len--)>0) { System.out.println(tempNode.getNumber()); tempNode=tempNode.getNextNode(); } } //第二種情形
        else { //記錄出隊的節點數
            int cnt=0; do { //數(m-1)下
                for(int j=1;j<(m-1);j++) { tempNode=tempNode.getNextNode(); } //出隊的節點
 System.out.println(tempNode.getNextNode().getNumber()); //記錄出隊的節點數
                cnt++; //刪除數到m的節點
                Node tempNode2=tempNode.getNextNode().getNextNode(); tempNode.setNextNode(tempNode2); //更新tempNode,從數到m的人下一個開始報數
                tempNode=tempNode2; } while (cnt!=this.length); } } }
複製代碼

運行結果:

9
5
2
10
8
1
4
3
7
6

======================================================================================

java移位運算符不外乎就這三種:<<(左移)、>>(帶符號右移)和>>>(無符號右移)。  
一、 左移運算符 
左移運算符<<使指定值的全部位都左移規定的次數。 
1)它的通用格式以下所示: 
value << num 
num 指定要移位值value 移動的位數。 
左移的規則只記住一點:丟棄最高位,0補最低位 
若是移動的位數超過了該類型的最大位數,那麼編譯器會對移動的位數取模。如對int型移動33位,實際上只移動了33%32=1位。 

2)運算規則 
按二進制形式把全部的數字向左移動對應的位數,高位移出(捨棄),低位的空位補零。 
當左移的運算數是int 類型時,每移動1位它的第31位就要被移出而且丟棄; 
當左移的運算數是long 類型時,每移動1位它的第63位就要被移出而且丟棄。 
當左移的運算數是byte 和short類型時,將自動把這些類型擴大爲 int 型。 

3)數學意義 
在數字沒有溢出的前提下,對於正數和負數,左移一位都至關於乘以2的1次方,左移n位就至關於乘以2的n次方 

4)計算過程: 
例如:3 <<2(3爲int型) 
1)把3轉換爲二進制數字0000 0000 0000 0000 0000 0000 0000 0011, 
2)把該數字高位(左側)的兩個零移出,其餘的數字都朝左平移2位, 
3)在低位(右側)的兩個空位補零。則獲得的最終結果是0000 0000 0000 0000 0000 0000 0000 1100, 
轉換爲十進制是12。 
移動的位數超過了該類型的最大位數, 
若是移進高階位(31或63位),那麼該值將變爲負值。下面的程序說明了這一點: 

Java代碼   收藏代碼
  1. // Left shifting as a quick way to multiply by 2.  
  2. public class MultByTwo {  
  3. public static void main(String args[]) {  
  4.    int i;  
  5.    int num = 0xFFFFFFE;   
  6.    for(i=0; i<4; i++) {  
  7.        num = num << 1;   
  8.      System.out.println(num);  
  9.    }  
  10.   }  
  11. }  


該程序的輸出以下所示: 

536870908 
1073741816 
2147483632 
-32 
注:n位二進制,最高位爲符號位,所以表示的數值範圍-2^(n-1) ——2^(n-1) -1,因此模爲2^(n-1)。 

二、 右移運算符  
右移運算符<<使指定值的全部位都右移規定的次數。 
1)它的通用格式以下所示: 
value >> num 
num 指定要移位值value 移動的位數。 
右移的規則只記住一點:符號位不變,左邊補上符號位 

2)運算規則: 
按二進制形式把全部的數字向右移動對應的位數,低位移出(捨棄),高位的空位補符號位,即正數補零,負數補1 
當右移的運算數是byte 和short類型時,將自動把這些類型擴大爲 int 型。 
例如,若是要移走的值爲負數,每一次右移都在左邊補1,若是要移走的值爲正數,每一次右移都在左邊補0,這叫作符號位擴展(保留符號位)(sign extension ),在進行右移 

操做時用來保持負數的符號。 


3)數學意義 
右移一位至關於除2,右移n位至關於除以2的n次方。 

4)計算過程 
11 >>2(11爲int型) 
1)11的二進制形式爲:0000 0000 0000 0000 0000 0000 0000 1011 
2)把低位的最後兩個數字移出,由於該數字是正數,因此在高位補零。 
3)最終結果是0000 0000 0000 0000 0000 0000 0000 0010。 
轉換爲十進制是3。 

35 >> 2(35爲int型) 
35轉換爲二進制:0000 0000 0000 0000 0000 0000 0010 0011  
把低位的最後兩個數字移出:0000 0000 0000 0000 0000 0000 0000 1000 
轉換爲十進制: 8 

5)在右移時不保留符號的出來 
右移後的值與0x0f進行按位與運算,這樣能夠捨棄任何的符號位擴展,以便獲得的值能夠做爲定義數組的下標,從而獲得對應數組元素表明的十六進制字符。 
例如 
Java代碼   收藏代碼
  1. public class HexByte {  
  2. public static public void main(String args[]) {  
  3. char hex[] = {  
  4. '0''1''2''3''4''5''6''7',   
  5. '8''9''a''b''c''d''e''f''   
  6. };  
  7. byte b = (byte0xf1;   
  8. System.out.println("b = 0x" + hex[(b >> 4) & 0x0f] + hex[b & 0x0f]);  
  9. }  
  10. }   


(b >> 4) & 0x0f的運算過程: 
b的二進制形式爲:1111 0001 
4位數字被移出:0000 1111 
按位與運算:0000 1111 
轉爲10進制形式爲:15 

b & 0x0f的運算過程: 
b的二進制形式爲:1111 0001 
0x0f的二進制形式爲:0000 1111 
按位與運算:0000 0001 
轉爲10進制形式爲:1 

因此,該程序的輸出以下: 
b = 0xf1 


三、無符號右移  
無符號右移運算符>>> 
它的通用格式以下所示: 
value >>> num 
num 指定要移位值value 移動的位數。 
無符號右移的規則只記住一點:忽略了符號位擴展,0補最高位 
無符號右移運算符>>> 只是對32位和64位的值有意義
相關文章
相關標籤/搜索