位运算必会20个

优秀程序员不得不知道的20个位运算技巧

一提起位运算,人们往往想到它的高效性,无论是嵌入式编程还是优化系统的核心代码,适当的运用位运算总是一种迷人的手段,或者当您求职的时候,在代码中写入适当的位运算也会让您的程序增加一丝亮点,最初当我读《编程之美》求“1的数目”时,我才开始觉得位运算是如此之美,后来读到 《Hacker‘s Delight》,感慨到Henry S.Warren把位运算运用的如此神出鬼没,很多程序都十分精妙,我觉得在一个普通的程序中大量运用这样的代码的人简直是疯了!但掌握简单的位运算技巧还是必要的,所以今天写这篇博文把我积累的一些位运算技巧分享给大家,这些技巧不会是如求“1的数目”的技巧,是最基本的一行位运算技巧!

Welcome To My BitTricks

1.获得int型最大值

[cpp] view plain copy

  1. int getMaxInt(){
  2. return (1 << 31) - 1;//2147483647, 由于优先级关系,括号不可省略
  3. }

另一种写法

[cpp] view plain copy

  1. int getMaxInt(){
  2. return ~(1 << 31);//2147483647
  3. }

另一种写法

[cpp] view plain copy

  1. int getMaxInt(){//有些编译器不适用
  2. return (1 << -1) - 1;//2147483647
  3. }

C语言中不知道int占几个字节时候

[java] view plain copy

  1. int getMaxInt(){
  2. return ((unsigned int) - 1) >> 1;//2147483647
  3. }

2.获得int型最小值

[cpp] view plain copy

  1. int getMinInt(){
  2. return 1 << 31;//-2147483648
  3. }

另一种写法

[cpp] view plain copy

  1. int getMinInt(){//有些编译器不适用
  2. return 1 << -1;//-2147483648
  3. }

3.获得long类型的最大值

C语言版

[cpp] view plain copy

  1. long getMaxLong(){
  2. return ((unsigned long) - 1) >> 1;//2147483647
  3. }

JAVA版

[java] view plain copy

  1. long getMaxLong(){
  2. return ((long)1 << 127) - 1;//9223372036854775807
  3. }

获得long最小值,和其他类型的最大值,最小值同理.

4.乘以2运算

[cpp] view plain copy

  1. int mulTwo(int n){//计算n*2
  2. return n << 1;
  3. }

5.除以2运算

[cpp] view plain copy

  1. int divTwo(int n){//负奇数的运算不可用
  2. return n >> 1;//除以2
  3. }

6.乘以2的m次方

[cpp] view plain copy

  1. int mulTwoPower(int n,int m){//计算n*(2^m)
  2. return n << m;
  3. }

7.除以2的m次方

[cpp] view plain copy

  1. int divTwoPower(int n,int m){//计算n/(2^m)
  2. return n >> m;
  3. }

8.判断一个数的奇偶性

[java] view plain copy

  1. boolean isOddNumber(int n){
  2. return (n & 1) == 1;
  3. }

9.不用临时变量交换两个数(面试常考)

C语言版

[cpp] view plain copy

  1. void swap(int *a,int *b){
  2. (*a) ^= (*b) ^= (*a) ^= (*b);
  3. }

通用版(一些语言中得分开写)

[java] view plain copy

  1. a ^= b;
  2. b ^= a;
  3. a ^= b;

10.取绝对值(某些机器上,效率比n>0  ?  n:-n 高)

[cpp] view plain copy

  1. int abs(int n){
  2. return (n ^ (n >> 31)) - (n >> 31);
  3. /* n>>31 取得n的符号,若n为正数,n>>31等于0,若n为负数,n>>31等于-1
  4. 若n为正数 n^0=0,数不变,若n为负数有n^-1 需要计算n和-1的补码,然后进行异或运算,
  5. 结果n变号并且为n的绝对值减1,再减去-1就是绝对值 */
  6. }

11.取两个数的最大值(某些机器上,效率比a>b ? a:b高)

通用版

[cpp] view plain copy

  1. int max(int a,int b){
  2. return b & ((a-b) >> 31) | a & (~(a-b) >> 31);
  3. /*如果a>=b,(a-b)>>31为0,否则为-1*/
  4. }

C语言版

[cpp] view plain copy

  1. int max(int x,int y){
  2. return x ^ ((x ^ y) & -(x < y));
  3. /*如果x<y x<y返回1,否则返回0,
  4. 、 与0做与运算结果为0,与-1做与运算结果不变*/
  5. }

12.取两个数的最小值(某些机器上,效率比a>b ? b:a高)

通用版

[cpp] view plain copy

  1. int min(int a,int b){
  2. return a & ((a-b) >> 31) | b & (~(a-b) >> 31);
  3. /*如果a>=b,(a-b)>>31为0,否则为-1*/
  4. }

C语言版

[cpp] view plain copy

  1. int min(int x,int y){
  2. return y ^ ((x ^ y) & -(x < y));
  3. /*如果x<y x<y返回1,否则返回0,
  4. 与0做与运算结果为0,与-1做与运算结果不变*/
  5. }

13.判断符号是否相同

[java] view plain copy

  1. boolean isSameSign(int x, int y){ //有0的情况例外
  2. return (x ^ y) >= 0; // true 表示 x和y有相同的符号, false表示x,y有相反的符号。
  3. }

14.计算2的n次方

[cpp] view plain copy

  1. int getFactorialofTwo(int n){//n > 0
  2. return 2 << (n-1);//2的n次方
  3. }

15.判断一个数是不是2的幂

[java] view plain copy

  1. boolean isFactorialofTwo(int n){
  2. return n > 0 ? (n & (n - 1)) == 0 : false;
  3. /*如果是2的幂,n一定是100... n-1就是1111....
  4. 所以做与运算结果为0*/
  5. }

16.对2的n次方取余

[java] view plain copy

  1. int quyu(int m,int n){//n为2的次方
  2. return m & (n - 1);
  3. /*如果是2的幂,n一定是100... n-1就是1111....
  4. 所以做与运算结果保留m在n范围的非0的位*/
  5. }

17.求两个整数的平均值

[java] view plain copy

  1. int getAverage(int x, int y){
  2. return (x + y) >> 1;

另一种写法

[java] view plain copy

  1. int getAverage(int x, int y){
  2. return ((x ^ y) >> 1) + (x & y);
  3. /*(x^y) >> 1得到x,y其中一个为1的位并除以2,
  4. x&y得到x,y都为1的部分,加一起就是平均数了*/
  5. }

下面是三个最基本对二进制位的操作

18.从低位到高位,取n的第m位

[java] view plain copy

  1. int getBit(int n, int m){
  2. return (n >> (m-1)) & 1;
  3. }

19.从低位到高位.将n的第m位置1

[java] view plain copy

  1. int setBitToOne(int n, int m){
  2. return n | (1 << (m-1));
  3. /*将1左移m-1位找到第m位,得到000...1...000
  4. n在和这个数做或运算*/
  5. }

20.从低位到高位,将n的第m位置0

[java] view plain copy

  1. int setBitToZero(int n, int m){
  2. return n & ~(1 << (m-1));
  3. /* 将1左移m-1位找到第m位,取反后变成111...0...1111
  4. n再和这个数做与运算*/
  5. }

另附一些对程序效率上没有实质提高的位运算技巧,一些也是位运算的常识(面试也许会遇到)

计算n+1

[cpp] view plain copy

  1. -~n

计算n-1

[cpp] view plain copy

  1. ~-n

取相反数

[java] view plain copy

  1. ~n + 1;

另一种写法

[java] view plain copy

  1. (n ^ -1) + 1;

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

[cpp] view plain copy

  1. x = a ^ b ^ x;

sign函数,参数为n,当n>0时候返回1,n<0时返回-1,n=0时返回0

[cpp] view plain copy

  1. return !!n - (((unsigned)n >> 31) << 1);

如果您知道实用的一行位运算技巧请留言,博主不胜感激,还有我总结的位运算难免有不健壮之处,请您多多批评。

时间: 2024-11-11 06:51:07

位运算必会20个的相关文章

必用位运算

引述: 使用位运算的两个优点 : 简单,效率高(计算机底层) 简单记忆 : 清零取反用与,位置一用或 ,交换用疑惑 参考: url 1.获得int型最大值 int getMaxInt(){ return (1 << 31) - 1;//2147483647, 由于优先级关系,括号不可省略 } 1.1另一种写法 int getMaxInt(){ return ~(1 << 31);//2147483647 } 2.获得int型最小值 int getMinInt(){ return 1

HDU 4317 位运算

[题意]: 在一个常规的NIM游戏里,你可以在每堆石子拿走任意数量的石子,问求使先手必败的情况下拿走石子数量的最小值. [知识点]: 位运算,DP [题解]: 一道精致的位运算的好题目,细节有不少. 具体解释在代码内. [代码]: 1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 #include <cmath> 5 #include <cstdlib> 6 #inc

POJ 1166 The Clocks 位运算与BFS

1.题意:有一组3*3的只有时针的挂钟阵列,每个时钟只有0,3,6,9三种状态:对时针阵列有9种操作,每种操作只对特点的几个时钟拨一次针,即将时针顺时针波动90度,现在试求从初试状态到阵列全部指向0的状态所需要的最小操作数的操作方案: 2.输入输出:输入给出阵列初始状态,0,1,2,3分别表示0,3,6,9:要求输出最快方案的操作序列: 3.分析:IOI 1994的考题,BFS是比较容易想到的方法之一,关键是如何简洁的表示和改变BFS过程中的阵列状态:这里使用位运算的方法:具体如下: 首先一共9

Java位运算经典实例

一 源码.反码.补码 正数的源码.反码.补码相同,例如5:            5的源码:101            5的反码:101            5的补码:101 负数的源码.反码.补码不同,例如-5:            -5的源码:10000101            -5的反码:111111010 (取反操作)            -5的补码:111111011 (补码加1操作) 计算机所有数据都以补码存储和运算. 二 位操作       位操作包含&,|,!分别表示

Java基本数据类型与位运算

Java基本数据类型与位运算 >>赋值运算符 赋值使用操作符“=”.它的意思是“取右边的值(即右值),把它复制给左边(即左值)”.右值可以是任何 常数.变量或者表达式 (只要它能 生成 一个值就行).但左值必须是一个明确的,已命名的变量.也就是说,必须有一个物理空间可以存储等号右边的值.分类 基本数据类型 与 类数据类型 的不同1. 对基本数据类型的赋值是很简单的.基本数据存储了实际的数值,而并非指向一个对象的引用,所以在为其赋值的时候,是直接将一个地方的内容复制到了另一个地方.2. 但是在为

【模拟+递归+位运算】POJ1753-Flip Game

由于数据规模不大,利用爆搜即可.第一次用位运算写的,但是转念一想应该用递归更加快,因为位运算没有剪枝啊(qДq ) [思路] 位运算:时间效率较低(172MS),有些辜负了位运算的初衷.首先将二维数组倒序看作一个二进制数num.我们假设1代表翻转,0代表不翻转,可以发现以下规律:0 xor 1=1,1 xor 1=0;0 xor 0=0,1 xor 0=1,恰巧满足异或运算.我们假设另一个二进制数i∈[0,2^16),通过异或运算就可以模拟出所有清形. 用check和i进行&操作可以求出以哪些位

进制、位运算笔记

进制 位运算 进制介绍 一种计数的方式,数值的表示形式. 常见的进制有:二进制.十进制.八进制和十六进制. 二进制: 0和1,C语言中表示0b开头或者0B开头. 八进制: 0,1,2,3,4,5,6,7 C语言中以0开头的数字,例如045 十进制: 自然数 十六进制: 0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F C语言中以0x或者0X开头的数字 进制之间的转换: 其他进制转换成十进制的三要素: 1. 数位:数码在一个数中所处的位置. 一个序列,从右往左数位依次是0,1,2,3

嵌入式C语言之位运算 &amp;..|.~.&gt;&gt;

在嵌入式编程中,掌握位运算在操作寄存器的时候很方便,由于之前在上位运算的时候没上,但是由于位运算的难度不是很大,自己编写程序,顺便做些总结. &   |   - 这三个位运算符号不难理解,但是要区别与逻辑运算符号&&  和|| 1.需要总结的是:假如要使寄存器的值为1的话,一般用 这个寄存器的值来| 上1 比如要将i的值变为1则可以使用    i   |=  1;    意思就是将i的值与上1的值再给i.同理要让一个变量的值变成0的话,将使用 &上0     例如   i&

NYOJ528 找球号(三)位运算

这个题用位运算就非常简单了,前提是首先熟悉位运算,这里用到一个异或运算,也就是 ^ 这个符号,他的运算规则是:相同为0,不同为1.知道了这个之后,就容易想到相同的两个数异或之后为0,所以下面很关键的一步,也是我想了好久也没想起来的一步,就是把所有的数都异或一遍,那么最后剩下的一定是那个一个的,还有一点需要注意就是任何数和0进行异或运算都还是他本身.下面是代码: 1 #include <iostream> 2 #include <cstdio> 3 4 using namespace