• 位运算计算与位运算应用


    位运算包括与,或,取反,异或,左移,右移等。

    一 位运算计算

    1 与运算:&

      操作符&将2个数的二进制位进行与操作,2个数对应的位都为1,运算结果为1;否则运算结果为0。

    比如 6&8,6的二进制为:0110   8的二进制为:1000。所以6&8 = 0000 = 0

    2 或运算:|

      操作符|将2个数的二进制位进行或操作,2个数对应的位有一个为1,运算结果为1;否则运算结果为0。

    比如 6&8,6的二进制为:0110   8的二进制为:1000。所以6&8 = 1110 = 14

    3 取反运算:~

      操作符~将每位二进制位取反,1变0,0变1。

    比如 ~6,6的二进制位为0110,~6 = ~0110 = 1001 = 9

    4 异或:^

      操作符^将2个数的每个二进制位异或,2个数对应的位相同,运算结果为0,否则运算结果为1。

    比如 6^10,6的二进制为0110,9的二进制为1010, 0110^1010 = 1100 = 12

    5 右移运算符:>>  右移运算分二种:逻辑右移和算术右移

      ①逻辑右移

    逻辑右移在移动过程中,左边位用0填充。比如1000 0011右移3位,变成0001 0000

      ②算术右移

    算术右移在移动过程中,左边位用符号位填充。比如1000 0011右移3位,变成1111 0000

    6 左移运算符:<<

      左移过程中,右边一律用0填充。0000 1100左移2位为0011 0000

    在实际的编程过程中,往往会用一个整数的不同位表示不同的数据信息。在访问该整数时,就需要通过位运算来获得或者改变整数的某几位数值。比如在Windows中创建文件时使用的Create数据结构: 
    struct 
    {
         PIO_SECURITY_CONTEXT SecurityContext; 
        ULONG Options; 
        USHORT POINTER_ALIGNMENT FileAttributes; 
        USHORT ShareAccess;
        ULONG POINTER_ALIGNMENT EaLength;
        PVOID EaBuffer; 
        LARGE_INTEGER AllocationSize;
     } Create; 
    通常会引用其中的Options如下: 
    Data->Iopb->Parameters.Create.Options 
    ULONG Options是一个Windows文件创建过程中的无符号长整数,指示在创建和打开文件时的不同选项。其中高8位指示了CreateDisposition参数(如FILE_OPEN,FILE_CREATE),低24位指示了CreateOptions参数(如FILE_DELETE_ON_CLOSE)。 为了得到CreateDisposition的值,采取下面的位操作:
     (Data->Iopb->Parameters.Create.Options >> 24) & 0x000000ff; 
    将该整数右移24位,再与0xff做与操作,即可获得CreateDisposition的值。

    二 位运算应用

    1.任何一个数和0异或是它的本身,和自身异或为0:


    a^0=a 
    a^a=0 
    利用上述性质,可以用来计算2个数的交换。
    大家应该知道,在计算机里,两个数互相交换,需要定义一个中间的变量来参与交换。如: 
    int tmp; 
    int a=10; 
    int b=20; 
    tmp=a; 
    a=b; 
    b=tmp; 
    上述代码计算之后,a和b的值完成交换,a的值为20,b的值为10。 
    如果用异或运算来交换2个数,可以如下方法: 
    int a=10; 
    int b=20; 
    a=a^b; 
    b=a^b; 
    a=a^b; 
    上述运行之后,a和b依然完成了值的交换,但由于是异或位运算,所以效率比上面的代码要高。 
    证明:
    a=10^20
    b=a^b=(10^20)^20=10^20^20=10^0=10
    a=a^b=10^20^10=10^10^20=0^20=20
    把上述代码,可以封装为一个交换2个数的函数如下: 
    void swap(int *a, int *b) 

        *a = *a ^ *b; 
        *b = *a ^ *b; 
        *a = *a ^ *b;
     }
    或者用宏来定义:
    #define SWAP(a,b)
    do {
         a = a^b;
         b = a^b;
         a = a^b;
    } while(0)
    但按照下面的方法来写一个函数,试着将两个数进行交换,是错误的(想想为什么?)
    void swap(int a, int b) 

        a = a ^ b; 
        b = a ^ b; 
        a = a ^ b;
     }

    2.将整数的第n位置位或清零:


    #define BITN (1《n) 
    置位:a |= BITN; 
    清零:a &= ~BITN

    3.清除整数a最右边的1。


    方法:a & (a – 1)//该运算将会清除掉整数a二进制中最右边的1。 
    问题:如何判断判断整数x的二进制中含有多少个1? 
    分析:此题是微软公司的一道笔试题。下面用&运算来解决此题。 代码如下: 
    int func(int x ) 
    {
        int countx = 0; 
        while ( x ) 
        { 
            countx++; 
            x = x&(x-1); 
        } 
        return countx; 
    }

    4.用异或运算设计一个只有一个指针域的双向链表:

    提示: 
    要实现该设计要求,需要记住链表的头结点和尾结点,并在链表结点的的next域存放前一个结点和后一个结点的异或值。即: 
    p->next=pl^pr;//头结点的左边结点为NULL,尾结点的右边结点为NULL。 
    在遍历的时候,从头结点往右遍历的方法: 
    pl=NULL;
    p=Head; 
    while(p!=Tail) 

        pr=pl^(p->next); 
        pl=p; 
        p=pr;
     } 
    从尾结点往左遍历的方法: 
    pr=NULL; 
    p=Tail; 
    while(p!=Tail)

        pl=pr^(p->next); 
        pr=p; 
        p=pl; 


    5.计算下面表达式的值


    (char)(127<<1)+1
    (char)(-1>>1)+1
    1<<2+3

    解答:
    (char)(127<<1)+1=(01111111<<1)+1=11111110+1=11111111=-1
    (char)(-1>>1)+1=(11111111>>1)+1=11111111+1=0
    1<<2+3=1<<(2+3)=1<<5=2^5=32(注意《和+的优先级)

      

      

  • 相关阅读:
    通过w3c方式 读取xml内容
    ssm项目 maven 项目pon.xml 配置
    myeclipse 2014新建maven web 项目步骤
    Maven学习
    常用正则学习
    Maven 那点事儿
    Chrome 里的请求报错 " Provisional headers are shown"
    php框架thinkphp3.2.3 配置文件bug
    $_GET $_POST $_REQUEST
    php检测函数
  • 原文地址:https://www.cnblogs.com/fengxing999/p/10930042.html
Copyright © 2020-2023  润新知