• 位运算的应用


    • 一.逻辑运算符 

      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;
      }

  • 相关阅读:
    perl教程
    信号量(semaphore)——POSIX信号量和System V信号量
    (C#习题) 杂题1
    (C#) 操作XML之遍历
    (C# 基础) Solution and Project
    (C#)枚举 Enumerations
    (WPF) 窗口间传参数
    (C#) 操作XML之查找
    (C#习题) 字符串
    (C#) VS类视图和对象浏览器图标
  • 原文地址:https://www.cnblogs.com/Kobe10/p/5759765.html
Copyright © 2020-2023  润新知