zoukankan      html  css  js  c++  java
  • 位运算的应用

    • 一.逻辑运算符 

      1.& 位与运算 

       1) 运算规则 

      位与运算的实质是将参与运算的两个数据,按对应的二进制数逐位进行逻辑与运算。例如:int型常量47进行位与运算的运算过程如下:

      4=0000 0000 0000 0100 &7 =0000 0000 0000 0111= 0000 0000 0000 0100

      对于负数,按其补码进行运算。例如:例如:int型常量-47进行位与运算的运算过程如下:-4=1111 1111 1111 1100 &7 =0000 0000 0000 0111= 0000 0000 0000 0100

      2) 典型应用 

      (1) 清零 

      清零:快速对某一段数据单元的数据清零,即将其全部的二进制位为0。例如整型数a=321对其全部数据清零的操作为a=a&0x0 321=0000 0001 0100 0001 &0=0000 0000 0000 0000

      = 0000 0000 0000 0000

      (2) 获取一个数据的指定位 

      获取一个数据的指定位。例如获得整型数a=的低八位数据的操作为a=a&0xFF321=

      0000 0001 0100 0001 & 0xFF =0000 0000 1111 11111

      = 0000 0000 0100 0001

      获得整型数a=的高八位数据的操作为a=a&0xFF00==a&0XFF00==

      321=0000 0001 0100 0001 & 0XFF00=1111 1111 0000 0000

      = 0000 0001 0000 0000

      (3)保留数据区的特定位 

      保留数据区的特定位。例如获得整型数a=的第7-8位(从0开始)位的数据操作为: 110000000

      321=0000 0001 0100 0001 & 384=0000 0001 1000 0000

      =0000 0001 0000 0000

      2. | 位或运算 

      1) 运算规则 

      位或运算的实质是将参与运算的两个数据,按对应的二进制数逐位进行逻辑或运算。例如:int型常量57进行位或运算的表达式为5|7,结果如下:5= 0000 0000 0000 0101

      | 7= 0000 0000 0000 0111=0000 0000 0000 0111

      2) 主要用途 

      (1) 设定一个数据的指定位。例如整型数a=321,将其低八位数据置为1的操作为a=a|0XFF321= 0000 0001 0100 0001 | 0000 0000 1111 1111=0000 0000 1111 1111

      逻辑运算符||与位或运算符|的区别 

      条件“或”运算符 (||) 执行 bool 操作数的逻辑“或”运算,但仅在必要时才计算第二个操作数。 x || y , x | y 不同的是,如果 x true,则不计算 y(因为不论 y 为何值,“或”操作的结果都为 true)。这被称作为“短路”计算。

      3. ^ 位异或 

       1) 运算规则 

      位异或运算的实质是将参与运算的两个数据,按对应的二进制数逐位进行逻辑异或运算。只有当对应位的二进制数互斥的时候,对应位的结果才为真。例如:int型常量57进行位异或运算的表达式为5^7,结果如下:5=0000 0000 0000 0101^7=0000 0000 0000 0111

      = 0000 0000 0000 0010

      2) 典型应用 

       (1)定位翻转 

      定位翻转:设定一个数据的指定位,将1换为00换为1。例如整型数a=321,,将其低八位数据进行翻位的操作为a=a^0XFF;

      (2)数值交换 

      数值交换。例如a=3,b=4。在例11-1中,无须引入第三个变量,利用位运算即可实现数据交换。以下的操作可以实现a,b两个数据的交换:

      a=a^b;

      b=b^a;

      a=a^b;

      4~ 位非 

      位非运算的实质是将参与运算的两个数据,按对应的二进制数逐位进行逻辑非运算。

       

      二.位移运算符

      1.位左移

      左移运算的实质是将对应的数据的二进制值逐位左移若干位,并在空出的位置上填0,最高位溢出并舍弃。例如int a,b;

      a=5;

      b=a<<2;

      则b=20,分析过程如下:

      (a)10=(5)10=(0000 0000 0000 0101)2

      b=a<<2;

      b=(0000 0000 0001 0100)2=(20)10

      从上例可以看出位运算可以实现二倍乘运算。由于位移操作的运算速度比乘法的运算速度高很多。因此在处理数据的乘法运算的时,采用位移运算可以获得较快的速度。

      提示 将所有对2的乘法运算转换为位移运算,可提高程序的运行效率

      2.位右移

      位右移运算的实质是将对应的数据的二进制值逐位右移若干位,并舍弃出界的数字。如果当前的数为无符号数,高位补零。例如:

      int (a)10=(5)10=(0000 0000 0000 0101)2

      b=a>>2;

      b=(0000 0000 0000 0001)2=(1)10

      如果当前的数据为有符号数,在进行右移的时候,根据符号位决定左边补0还是补1。如果符号位为0,则左边补0;但是如果符号位为1,则根据不同的计算机系统,可能有不同的处理方式。可以看出位右移运算,可以实现对除数为2的整除运算。

      提示 将所有对2的整除运算转换为位移运算,可提高程序的运行效率

      3.复合的位运算符

      在C语言中还提供复合的位运算符,如下:

      &=、!=、>>=、<<=和^=

      例如:a&=0x11等价于 a= a&0x11,其他运算符以此类推。

      不同类型的整数数据在进行混合类型的位运算时,按右端对齐原则进行处理,按数据长度大的数据进行处理,将数据长度小的数据左端补0或1。例如char a与int b进行位运算的时候,按int 进行处理,char a转化为整型数据,并在左端补0。

      补位原则如下:

      1) 对于有符号数据:如果a为正整数,则左端补0,如果a 为负数,则左端补1。

      2) 对于无符号数据:在左端补0。

      4.例子

      例11-2 获得一个无符号数据从第p位开始的n位二进制数据。假设数据右端对齐,第0位二进制数在数据的最右端,获得的结果要求右对齐。

      #include

      /*getbits:获得从第p位开始的n位二进制数 */

      unsigned int getbits(unsigned int x, unsigned int p, unsigned n)

      {

      unsigned int a;

      unsigned int b;

      a=x>>(p+1);

      b=~(~0<<n);< n);<="" p="">

      return a&b;

      }

      提示在某一平台进行程序开发时,首先要求了解此系统的基本数据类型的有效范围,对涉及的位运算进行评估,特别是要对边界数据进行检测,确保计算正确。





    • (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)

      #include <stdio.h>
      //设置x的第y位为1
      #define setbit(x,y) (x)|=(1<<(y-1))
      //得到x的第y位的值
      #define BitGet(Number,pos) ((Number)>>(pos-1)&1)
      //打印x的值
      #define print(x) printf("%d ",x)
      //将整数(4个字节)循环右移动k位
      #define Rot(a,k) ((a)<<(k)|(a)>>(32-k))
      //判断a是否为2的幂次数
      #define POW2(a) ((((a)&(a-1))==0)&&(a!=0))
      #define OPPX(x) (~(x)+1)
      //返回X,Y 的平均值
      int average(int x, int y)
      {    
      return (x&y)+((x^y)>>1);
      }
      //判断a是否为2的幂次数

      bool power2(int x)
      {
          return ((x&(x-1))==0)&&(x!=0);
      }
      //x与y互换
      void swap(int& x , int& y)
      {
           x ^= y;
           y ^= x;
           x ^= y;
      }

      int main()
      {
      int a=0x000D;
      print(a);
      int b=BitGet(a,2);
      print(b);

      setbit(a,2);
      print(a);
      print(BitGet(a,2));
      int c=Rot(a,33);
      print(c);
      print(BitGet(c,5));
      printf("8+5=%d ",average(8,692));

      int i;
      for (i=0;i<1000;i++)
      {
         if (POW2(i))//调用power2(i)
          {
           printf("%-5d",i);
          }
      }
      printf(" ");

      int x=10,y=90;
      swap(x,y);
      print(x);
      print(y);
      print(OPPX(-705));
      return 0;
      }

  • 相关阅读:
    解决ListView异步加载数据之后不能点击的问题
    android点击实现图片放大缩小 java技术博客
    关于 数据文件自增长 的一点理解
    RAC 实例不能启动 ORA1589 signalled during ALTER DATABASE OPEN
    Linux 超级用户的权利
    RAC 实例 迁移到 单实例 使用导出导入
    Shell 基本语法
    Linux 开机引导与关机过程
    RAC 实例不能启动 ORA1589 signalled during ALTER DATABASE OPEN
    Oracle RAC + Data Guard 环境搭建
  • 原文地址:https://www.cnblogs.com/Kobe10/p/5759765.html
Copyright © 2011-2022 走看看