zoukankan      html  css  js  c++  java
  • php的移位符运算

    移位运算符
    移位运算符就是在二进制的基础上对数字进行平移。按照平移的方向和填充数字的规则分为三种:<<(左移)、>>(带符号右移)和>>>(无符号右移)。
    在移位运算时,byte、short和char类型移位后的结果会变成int类型,对于byte、short、char和int进行移位时,规定实际移 动的次数是移动次数和32的余数,也就是移位33次和移位1次得到的结果相同。移动long型的数值时,规定实际移动的次数是移动次数和64的余数,也就 是移动66次和移动2次得到的结果相同。
    三种移位运算符的移动规则和使用如下所示:
    <<运算规则:按二进制形式把所有的数字向左移动对应的位数,高位移出(舍弃),低位的空位补零。
    语法格式:
    需要移位的数字 << 移位的次数
    例如: 3 << 2,则是将数字3左移2位
    计算过程:
    3 << 2
    首先把3转换为二进制数字0000 0000 0000 0000 0000 0000 0000 0011,然后把该数字高位(左侧)的两个零移出,其他的数字都朝左平移2位,最后在低位(右侧)的两个空位补零。则得到的最终结果是0000 0000 0000 0000 0000 0000 0000 1100,则转换为十进制是12.数学意义:
    在数字没有溢出的前提下,对于正数和负数,左移一位都相当于乘以2的1次方,左移n位就相当于乘以2的n次方。
    >>运算规则:按二进制形式把所有的数字向右移动对应巍峨位数,低位移出(舍弃),高位的空位补符号位,即正数补零,负数补1.
    语法格式:
    需要移位的数字 >> 移位的次数
    例如11 >> 2,则是将数字11右移2位
    计算过程:11的二进制形式为:0000 0000 0000 0000 0000 0000 0000 1011,然后把低位的最后两个数字移出,因为该数字是正数,所以在高位补零。则得到的最终结果是0000 0000 0000 0000 0000 0000 0000 0010.转换为十进制是3.数学意义:右移一位相当于除2,右移n位相当于除以2的n次方。
    >>>运算规则:按二进制形式把所有的数字向右移动对应巍峨位数,低位移出(舍弃),高位的空位补零。对于正数来说和带符号右移相同,对于负数来说不同。
    其他结构和>>相似。
    小结
    二进制运算符,包括位运算符和移位运算符,使程序员可以在二进制基础上操作数字,可以更有效的进行运算,并且可以以二进制的形式存储和转换数据,是实现网络协议解析以及加密等算法的基础。

    移位运算

    要点 1 它们都是双目运算符,两个运算分量都是整形,结果也是整形。

         2 "<<" 左移:右边空出的位上补0,左边的位将从字头挤掉,其值相当于乘2。

         3 ">>"右移:右边的位被挤掉。对于左边移出的空位,如果是正数则空位补0,若为负数,可能补0或补1,这取决于所用的计算机系统。

         4 ">>>"运算符,右边的位被挤掉,对于左边移出的空位一概补上0。

    位运算符的应用 (源操作数s 掩码mask)

    (1) 按位与-- &

    1 清零特定位 (mask中特定位置0,其它位为1,s=s&mask)

    2 取某数中指定位 (mask中特定位置1,其它位为0,s=s&mask)

    (2) 按位或-- |

        常用来将源操作数某些位置1,其它位不变。 (mask中特定位置1,其它位为0 s=s|mask)

    (3) 位异或-- ^

    1 使特定位的值取反 (mask中特定位置1,其它位为0 s=s^mask)

    2 不引入第三变量,交换两个变量的值 (设 a=a1,b=b1)

        目 标           操 作              操作后状态

    a=a1^b1         a=a^b              a=a1^b1,b=b1

    b=a1^b1^b1      b=a^b              a=a1^b1,b=a1

    a=b1^a1^a1      a=a^b              a=b1,b=a1

    二进制补码运算公式:

    -x = ~x + 1 = ~(x-1)

    ~x = -x-1

    -(~x) = x+1

    ~(-x) = x-1

    x+y = x - ~y - 1 = (x|y)+(x&y)

    x-y = x + ~y + 1 = (x|~y)-(~x&y)

    x^y = (x|y)-(x&y)

    x|y = (x&~y)+y

    x&y = (~x|y)-~x

    x==y:    ~(x-y|y-x)

    x!=y:    x-y|y-x

    x< y:    (x-y)^((x^y)&((x-y)^x))

    x<=y:    (x|~y)&((x^y)|~(y-x))

    x< y:    (~x&y)|((~x|y)&(x-y))//无符号x,y比较

    x<=y:    (~x|y)&((x^y)|~(y-x))//无符号x,y比较

    应用举例

    (1) 判断int型变量a是奇数还是偶数           

    a&1   = 0 偶数

    a&1 =   1 奇数

    (2) 取int型变量a的第k位 (k=0,1,2……sizeof(int)),即a>>k&1

    (3) 将int型变量a的第k位清0,即a=a&~(1<<k)

    (4) 将int型变量a的第k位置1, 即a=a|(1<<k)

    (5) int型变量循环左移k次,即a=a<<k|a>>16-k   (设sizeof(int)=16)

    (6) int型变量a循环右移k次,即a=a>>k|a<<16-k   (设sizeof(int)=16)

    (7)整数的平均值

    对于两个整数x,y,如果用 (x+y)/2 求平均值,会产生溢出,因为 x+y 可能会大于INT_MAX,但是我们知道它们的平均值是肯定不会溢出的,我们用如下算法:

    int average(int x, int y)   //返回X,Y 的平均值

    {   

         return (x&y)+((x^y)>>1);

    }

    (8)判断一个整数是不是2的幂,对于一个数 x >= 0,判断他是不是2的幂

    boolean power2(int x)

    {

        return ((x&(x-1))==0)&&(x!=0);

    }

    (9)不用temp交换两个整数

    void swap(int x , int y)

    {

        x ^= y;

        y ^= x;

        x ^= y;

    }

    (10)计算绝对值

    int abs( int x )

    {

    int y ;

    y = x >> 31 ;

    return (x^y)-y ;        //or: (x+y)^y

    }

    (11)取模运算转化成位运算 (在不产生溢出的情况下)

             a % (2^n) 等价于 a & (2^n - 1)

    (12)乘法运算转化成位运算 (在不产生溢出的情况下)

             a * (2^n) 等价于 a<< n

    (13)除法运算转化成位运算 (在不产生溢出的情况下)

             a / (2^n) 等价于 a>> n

            例: 12/8 == 12>>3

    (14) a % 2 等价于 a & 1       

    (15) if (x == a) x= b;

                else x= a;

            等价于 x= a ^ b ^ x;

    (16) x 的 相反数 表示为 (~x+1)

    Java实例操作:

    1. public class URShift {
    2.     
    3.     public static void main(String[] args) {
    4.         int i = -1;
    5.         i >>>= 10;
    6.         //System.out.println(i);
    7.         mTest();
    8.     }
    9.     
    10.     public static void mTest(){
    11.         //左移
    12.         int i = 12; //二进制为:0000000000000000000000000001100
    13.         i <<= 2; //i左移2位,把高位的两位数字(左侧开始)抛弃,低位的空位补0,二进制码就为0000000000000000000000000110000
    14.         System.out.println(i); //二进制110000值为48;
    15.         System.out.println("<br>");
    16.         
    17.         //右移
    18.         i >>=2; //i右移2为,把低位的两个数字(右侧开始)抛弃,高位整数补0,负数补1,二进制码就为0000000000000000000000000001100
    19.         System.out.println(i); //二进制码为1100值为12
    20.         System.out.println("<br>");
    21.         
    22.         //右移example
    23.         int j = 11;//二进制码为00000000000000000000000000001011
    24.         j >>= 2; //右移两位,抛弃最后两位,整数补0,二进制码为:00000000000000000000000000000010
    25.         System.out.println(j); //二进制码为10值为2
    26.         System.out.println("<br>");
    27.         
    28.         byte k = -2; //转为int,二进制码为:0000000000000000000000000000010
    29.         k >>= 2; //右移2位,抛弃最后2位,负数补1,二进制吗为:11000000000000000000000000000
    30.         System.out.println(k); //二进制吗为11值为2
    31.     }
    32.     
    33. }

    移位运算符面向的运算对象也是二进制的 “位”。 可单独用它们处理整数类型(主类型的一种)。左移位运算符(<<)能将运算符左边的运算对象向左移动运算符右侧指定的位数(在低位补0)。 “有符号”右移位运算符(>>)则将运算符左边的运算对象向右移动运算符右侧指定的位数。“有符号”右移位运算符使用了“符号扩展”:若值为正,则在高位插入0;若值为负,则在高位插入1。Java也添加了一种“无符号”右移位运算符(>>>),它使用了“零扩展”:无论正负,都在高位插入0。这一运算符是C或C++没有的。  
        若对char,byte或者short进行移位处理,那么在移位进行之前,它们会自动转换成一个int。只有右侧的5个低位才会用到。这样可防止我们在一个int数里移动不切实际的位数。若对一个long值进行处理,最后得到的结果也 是long。此时只会用到右侧的6个低位,防止移动超过long值里现成的位数。但在进行“无符号”右移位时,也可能遇到一个问题。若对byte或 short值进行右移位运算,得到的可能不是正确的结果(Java   1.0和Java   1.1特别突出)。它们会自动转换成int类型,并进行右移位。但“零扩展”不会发生,所以在那些情况下会得到-1的结果。

  • 相关阅读:
    leetcode 350. Intersection of Two Arrays II
    leetcode 278. First Bad Version
    leetcode 34. Find First and Last Position of Element in Sorted Array
    leetcode 54. Spiral Matrix
    leetcode 59. Spiral Matrix II
    leetcode 44. Wildcard Matching
    leetcode 10. Regular Expression Matching(正则表达式匹配)
    leetcode 174. Dungeon Game (地下城游戏)
    leetcode 36. Valid Sudoku
    Angular Elements
  • 原文地址:https://www.cnblogs.com/xiager/p/6844399.html
Copyright © 2011-2022 走看看