Java之整數運算


  Java的整數運算遵循四則運算規則,可以使用任意嵌套的小括號。四則運算規則和初等數學一致。例如:

public class Main {
    public static void main(String[] args) {
    	int i=(100+200)*(99-88);//3300
    	int n=7*(5+(i-9));//23072
    	System.out.println(i);
    	System.out.println(n);
    }
}

   輸出

3300
23072

   整數運算的數值不但是精確的,而且整數運算永遠是精確的,即使是出發,因為兩個整數相除只得到結果的整數部分,不進行四舍五入

int x=11/3;

   求余運算

int x=11%3;

   整數除法對於被除數為0運行時報錯,但編譯時不報錯

 

 

   溢出

  整數由於存在范圍限制,如果計算結果超出了范圍,就會產生溢出,而溢出不會報錯而會得到一個奇怪的結果。

public class Main {
    public static void main(String[] args) {
    	int x=2147483640;
    	int y=15;
    	int sum=x+y;
    	System.out.println(sum);
    }
}

   運行結果

-2147483641

   要解釋上述結果,我們把整數2147483640和15換成二進制做加法

   0111  1111 1111  1111 1111  1111  1111 1000

   +   0000 0000 0000 0000 0000 0000 0000 1111

     1000 0000 0000 0000 0000 0000 0000 0111

  由於最高位計算結果為1,因此加法結果變成了一個負數

  要解決上面的文件,可以把int換成long類型,由於long可表示的整型范圍更大,所以結果不會溢出

public class Main {
    public static void main(String[] args) {
    	long x=2147483640;
    	long y=15;
    	long sum=x+y;
    	System.out.println(sum);
    }
}

   還有一種簡寫的運算符,即+=,-=,*=,/=,使用方法如下

n+=100; //相當於n=n+100
n-=100;//相當於n=n-100

   自增/自減

  Java還提供了++運算和--運算,它們可以對一個整數進行加1和減1的操作:

public class Main {
    public static void main(String[] args) {
    	int n=100;
    	n++;
    	System.out.println(n);
    	n--;
    	System.out.println(n);
    }
}

   注意++寫在前面和后面計算結果是不同的,++n表示先加1再引用n,n++表示先引用n再加1。不建議把++運算混入到常規運算中,容易自己把自己搞懵了。

  移位運算

  在計算機中,整數總是以二進制的形式表示。例如,int類型的整數7使用4字節表示的二進制如下:

   00000000 00000000 00000000 00000111

  可以對整數進行移位運算。對整數7左移1位將得到整數14,左移2位將得到整數28

int n = 7;       // 00000000 00000000 00000000 00000111 = 7
int a = n << 1;  // 00000000 00000000 00000000 00001110 = 14
int b = n << 2;  // 00000000 00000000 00000000 00011100 = 28
int c = n << 28; // 01110000 00000000 00000000 00000000 = 1879048192
int d = n << 29; // 11100000 00000000 00000000 00000000 = -536870912

   左移29位時,由於最高位變成了1,因此結果變成了負數

  類似地對證書7進行右移結果如下

int n = 7;       // 00000000 00000000 00000000 00000111 = 7
int a = n >> 1;  // 00000000 00000000 00000000 00000011 = 3
int b = n >> 2;  // 00000000 00000000 00000000 00000001 = 1
int c = n >> 3;  // 00000000 00000000 00000000 00000000 = 0

   如果對一個負數進行右移,最高位1不動,結果仍然是一個負數

int n = -536870912;
int a = n >> 1;  // 11110000 00000000 00000000 00000000 = -268435456
int b = n >> 2;  // 10111000 00000000 00000000 00000000 = -134217728
int c = n >> 28; // 11111111 11111111 11111111 11111110 = -2

   還有一種不帶符號的右移運算,使用>>>,它的特點是符號位跟着動,因此,對一個負數進行>>>右移,它會變成正數,原因是最高位的1變成了0

int n = -536870912;
int a = n >>> 1;  // 01110000 00000000 00000000 00000000 = 1879048192
int b = n >>> 2;  // 00111000 00000000 00000000 00000000 = 939524096
int c = n >>> 29; // 00000000 00000000 00000000 00000111 = 7
int d = n >>> 31; // 00000000 00000000 00000000 00000001 = 1

   對byte和short類型進行位移時,會首先轉換為int再進行位移

  左移實際上就是不斷地*2,右移實際上就是不斷地/2

  位運算

  位運算是按位進行與,或,非和異或的運算。

  與運算的規則是,必須兩個數同時為1,結果才為1

n=0 & 0;//0
n=0 & 1;//0
n=1 & 0;//0
n=1 & 1;//1

   或運算的規則是,只要任意一個為1,結果就為1

n = 0 | 0; // 0
n = 0 | 1; // 1
n = 1 | 0; // 1
n = 1 | 1; // 1

   非運算的規則是,0和1呼喚

n = ~0; // 1
n = ~1; // 0

   異或運算的規則是,如果兩個數不同,結果為1,否則為0

n = 0 ^ 0; // 0
n = 0 ^ 1; // 1
n = 1 ^ 0; // 1
n = 1 ^ 1; // 0

   對於兩個整數的運算,實際上就是按位對齊,然后依次對每一位進行運算。例如

public class Main {
    public static void main(String[] args) {
    	int i = 167776589;
    	int n = 167776512;
    	System.out.println(i&n);
    }
}

   運行結果

167776512

   上述按位與運算實際上可以看作兩個整數表示的IP地址10.0.17.7710.0.17.0,通過與運算,可以快速判斷一個IP是否在給定的網段內。

  運算優先級

  在Java的計算表達式中,運算優先級從高到低依次是:

  

  • ()
  • ! ~ ++ --
  • * / %
  • + -
  • << >> >>>
  • &
  • |
  • += -= *= /=

  記不住也沒關系,只需要加括號就可以保證運算的優先級正確。

  類型的自動提升與強制轉型

  在運算過程中,如果參與運算的兩個數類型不一致,那么計算結果為較大類型的整型。例如,shortint計算,結果總是int,原因是short首先自動被轉型為int

public class Main {
    public static void main(String[] args) {
    	short s = 1234;
    	int i = 123456;
    	int x = s + i; //s自動轉換為int
    	short y = s + i;//編譯錯誤
    }
}

   也可以將結果強制轉型,即將大范圍的整數轉型為小范圍的整數。強制轉型使用(類型),例如,將int強制轉型為short

int i=12345;
short s = (short) i;//12345

   超出范圍的強制轉型會得到錯誤的結果,原因是轉型時,int的兩個高位直接直接被扔掉,僅保留了低位的兩個字節。

  舉例說明

public class Main {
    public static void main(String[] args) {
        int i1 = 1234567;
        short s1 = (short) i1; // -10617
        System.out.println(s1);
        int i2 = 12345678;
        short s2 = (short) i2; // 24910
        System.out.println(s2);
    }
}

   結果

-10617
24910

   為什么結果是-10617和24910呢

  首先把1234567轉換成二進制並且使用8位分割成4份

       00000000 00010010 11010110 10000111‬

  強制轉換成short類型或高位被拋棄留下低位兩個字節

  11010110 10000111

  最高位為1是負數,負數是以補碼的形式存儲在計算機內需要轉換成原碼

  原碼等於補碼-1后除符號位取反

  補碼-1結果

  11010110 10000110

  除符號位取反得到原碼

  10101001 01111001

  最高位為1所以是負數101001 01111001即-10617

  同理計算12345678去掉高兩位后剩下的最高位為0是正數則補碼和原碼是一樣的

  練習

  計算自然數之和

public class Main {
    public static void main(String[] args) {
        int n=100;
        int sum=0;
        for(int i=1;i<=n;i++) {
        	sum=sum+i;
        }
        System.out.println(sum);
    }
}

   小結

  整數運算的結果永遠都是精確的

  運算結果會自動提升

  可以強制轉型,但超出范圍的強制轉型會得到錯誤的結果

  應該選擇合適范圍的整型(intlong),沒有必要為了節省內存而使用byteshort進行整數運算。

  


免責聲明!

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



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