• 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进行整数运算。

      

  • 相关阅读:
    iOS:图片相关(19-05-09更)
    iOS:文字相关(19-01-08更)
    iOS:通信录(完成)(18-01-18更)
    Swift 中的Closures(闭包)详解
    Swift 中的高阶函数和函数嵌套
    Swift API设计原则
    Swift下CoreData的使用
    iOS 使用贝塞尔曲线绘制路径
    iOS CALayer使用
    iOS 多线程的使用
  • 原文地址:https://www.cnblogs.com/minseo/p/11727398.html
Copyright © 2020-2023  润新知