C++: 位操作

来源:互联网 发布:怎么查看端口号被占用 编辑:程序博客网 时间:2024/06/05 19:36

使用位操作加快运行

  • 位运算的知识
  • 有效的计算2乘以8的方法
    • 快速求取一个整数的7倍
  • 实现位操作求两个数的平均值
    • 引申利用位运算计算数的绝对值
  • 不用除法操作符实现两个正整数的除法
    • 方法一
    • 方法二递归求解
    • 方法三移位操作
    • 引申1用逻辑运算实现加法运算
    • 引申2如何只用逻辑运算实现乘法运算

位运算的知识

(1)常用的等式: -n = ~(n-1) = ~n+1
(2)获取整数n的二进制中最后一个 1:n&(-n) 或者 n&~(n-1)。例如,n = 010100, 则 -n = 101100,n&(-n) = 000100
(3)去掉正数n的二进制总的最后一个1:n&(n-1),如 n=010100, n-1 = 010011, n&(n-1)=010000

有效的计算2乘以8的方法

虽然直接进行乘法操作符运算也可以进行2*8,但是这种方法并非最优,通过移位的方法会比较高效。将一个数左移n位,相当于乘以了2的n次方。
常规的乘法运算也可以实现,但CPU直接支持位运算,效率最高,所以操作最有效的方法是2<<3

快速求取一个整数的7倍

( X < < 3 ) - X

注意:由于 -的优先级高于 << 所以不能去掉括号,否则结果不正确

实现位操作求两个数的平均值

求解平均数的方法就是将两者相加,然后除以2,以变量x与y为例,两者的平均数为(x+y)/2.

但是采用上述方法,会存在一个问题,当两个数比较大时,如两者的和大于了机器位数能够表示的最大值,可能会存在数据溢出的情况,而采用位运算的方法则可以避免这一问题,(x&y)+((x^y)>>1) 就是求解变量x与y的平均数,且位运算相比除法运算,效率更高。

对于表达式(x&y)+((x^y)>>1) 中,x&y表示的是取出x与y二进制位数中都为1的所有位,x^y表示的是x与y中有一个为1的所有位,右移1位相当于执行除以2运算。
整个表达式实际上可以分为两部分,第一部分是都为1的部分,因为相同,所以直接相加即可;而第二部分是x为1,y为0的部分以及x为0,y为1的部分,两部分加起来再除以2,然后跟前面的相加就可以表示两者的平均数了。

引申:利用位运算计算数的绝对值

对一个负数,右移31位后变成 0xffffffff
对一个正数,右移31位后变成0x00000000
而0xffffffff^x + x = -1 ;因为1011^1111 = 0100,任何数与1111异或,实质是把x的0和1进行颠倒计算。
如果用变量y表示x右移31位,(x^y)-y 则表示的是x的绝对值

不用除法操作符实现两个正整数的除法

方法一:

根据除法运算的原理进行减法操作,对除数循环减去被除数,减一次结果加一,直到刚好减为0或余数小于被除数为止

int div( int a, int b ){    int result = 0;    if( b==0 )    {        cout << "除数不能为0" << endl;        return result;    }    while( a>b )    {        result++;        a = a-b;    }    return result;}

方法二:递归求解

这里写图片描述

方法三:移位操作

这里写图片描述
这里写图片描述

引申1:用逻辑运算实现加法运算

实现两个正整数相加,一般直接使用加号运算符即可。根据题目中的要求,与上例中的方法二类似,可以通过移位操作符来进行正整数的加法运算。例如,5与7求和,转换为二进制求和为101与111求和,其二进制结果为1100.对于二进制的加法而言,1+1=0, 1+0=1, 0+0=0,通过对比位运算中的异或方法,不难发现,此方法与位运算中的异或类似。那么第一个数值就是:tempNum1 = num1^num2;0+0的进位是0,0+1的进位是0,只有1+1的进位是有效的,该思路与位运算的&运算相似,所以可以先 num1&num2,由于进位是进到高一位的,与<<运算很相似,同时num1和num2相互&之后,如果结果为0,那么久不存在进位,运算完成,所以可以用递归的思想实现。
这里写图片描述

引申2:如何只用逻辑运算实现乘法运算

此乘法,不大懂。。。
这里写图片描述
这里写图片描述

0 0
原创粉丝点击