C入门---位运算
程序中的所有数在计算机内存中都是以二进制的形式储存的。位运算直接对整数在内存中的二进制位进行操作。由于位运算直接对内存数据进行操作,不需要转成十进制,因此处理速度非常快。
(1),与(&)运算
"&"运算通常用于二进制取位操作,例如一个数 & 1 的结果就是取二进制的最末位。这可以用来判断一个整数的奇偶,二进制的最末位为0表示该数为偶数,最末位为1表示该数为奇数。
(2),或(|)运算
”|“运算通常用于二进制特定位上的无条件赋值,例如一个数 | 1 的结果就是把二进制最末位强行变成1。如果需要把二进制最末位变成0,对这个数| 1之后再减1就可以了,其实际意义就是把这个数强行变成最接近的偶数。
(3),异或(^)运算
"^"运算通常用于对二进制的特定一位进行取反操作,因为异或可以这样定义: 0和1 异或0都不变,异或1则取反。
"^"运算的逆运算是它本身,也就是说两次异或同一个数最后结果不变,即(a^b)^b = a。”^"运算可以用于简单的加密,比如你想对一个朋友说1314520,但怕别人知道,于是双方约定拿生日19800205作为密钥,1314520 ^ 19800205 = 20590165, 于是就把20590165告诉这个朋友。你的朋友再次计算20590165^19800205的值,得到1314520,于是它就明白了你的意图。
加法和减法互为逆运算,并且加法满足交换律。可以写出一个不需要临时变量的swap函数
void swap(int a, int b)
{
a = a + b;
b = a - b;
a = a - b;
}
由于^的逆运算是它本身,于是就有了一个很特别的swap过程:
void swap(int a, int b)
{
a = a ^ b;
b = a ^ b;
a = a ^ b;
}
(4),取反(~)运算
“~”运算的定义是把内存中的0和1全部取反。使用“~”运算时要格外小心,需要注意整数类型有没有符号。如果“~”的对象是无符号整数(不能表示负数),那么得到的值就是它与该类型上界的差。因为无符号类型的数是用00到$FFFF依次表示的。下面的程序返回65435。
#include <stdio.h>
int main()
{
unsigned short a = 100;
a = ~a;
printf("%d\n",a);
return 0;
}
如果“~”的对象是有符号的整数,情况就不一样了, 稍后会提到。
(5),左移(<<)运算
a << b 表示把 a 转为二进制后左移 b 位(在后面添b个0)。如100的二进制为1100100,而110010000转成十进制是400.可以看出 a<< b的值实际上就是a 乘以 2的 b次方,因为在二进制数后面添加一个0 就相当于该数乘以2.
通常认为 a <<1 比 a * 2更快,因为前者是更底层的操作,因此程序中乘以2的操作请尽量用左移一位来代替。
定义一些常量可能会用到 <<运算。可以方便地用(1 << 16) -1来表示65535.很多算法和数据结构要求数据规模必须是2的幂,此时可以用<<来定义Max_N等常量。
(6),右移(>>)运算
和<<相似,a >> b 表示二进制右移b位(去掉末b位),相当于a除以2的b次方(取整)。此外也经常用 >> 1来代替除以2,比如二分查找, 堆的插入操作等。想办法用>>代替除法运算,可以使程序效率大大提高。最大公约数的二进制算法用除以2操作来代替mod运算,效率可以提高60%。
常见的二进制位的变换操作
| 功能 | 示例 | 位运算 |
| 去掉最后一位 | (101101--->10110) | x >> 1 |
| 在最后加一个0 | (101101--->1011010) | x << 1 |
| 在最后加一个1 | (101101--->1011011) | (x << 1) + 1 |
| 把最后一位变成1 | (101100--->101101) | x | 1 |
| 把最后一位变成0 | (101101--->101100) | (x|1)-1 |
| 最后一位取反 | (101101--->101100) | x ^ 1 |
| 把右数第k位变成1 | (101001--->101101, k = 3) | x | (1 << (k -1)) |
| 把右数第k位变成0 | (101101--->101001,k = 3) | x & ~(1 <<(k -1)) |
| 右数第K位取反 | (101001--->101101,K= 3) | x ^(1 << (k - 1)) |
| 取末位三位 | (1101101--->101) | x & 7 |
| 取末K位 | (1101101--->1101,k = 5) | x & ((1 << k ) -1) |
| 取右数第 k位 | (1101101--->1, k = 4) | x >>(k -1) &1 |
| 把末K位变成1 | (101001--->101111, k = 4) | x | ((1 << k ) -1) |
| 末K位取反 | (101001--->100110, k = 4) | x ^ ((1<<k ) - 1) |
| 去掉整数最右边的1 | (100101111--->10010110) | x & ( x - 1) |
| 把右边连续的1变成0 | (100101111--->100100000) | x & ( x + 1) |
| 把右起第一个0 变成1 | (100101111--->100111111) | x | (x + 1) |
| 把右边连续的0变成1 | (11011000--->11011111) | x | (x - 1) |
| 去掉右起第一个1 的左边 | (100101000--->1000) |
x & (x ^(x -1)) |
| 取右边连续的1 | (100101111--->1111) |
(x ^(x+1)) >> 1 |
在实际的编程过程中,往往会用一个整数的不同位表示不同的数据信息。在访问该整数时,就需要通过位运算来获得或者改变整数的某几位数值。比如在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的值。
(2)将第n 位置位或清零。
#define BITN (1 << n)
置位: a |= BITN;
清零: a &= ~BITN;
(3)清除整数a最右边的1
方法: a & (a -1)
问题: 如何判断整数x的二进制中含有多少个1?
int func(x)
{
int countx = 0;
while(x)
{
countx ++;
x = x & (x -1);
}
return countx;
}
(4)将一个整数对齐到n:
a = (a + n -1) & ~(n -1)
C入门---位运算的更多相关文章
- C#中缓存的使用 ajax请求基于restFul的WebApi(post、get、delete、put) 让 .NET 更方便的导入导出 Excel .net core api +swagger(一个简单的入门demo 使用codefirst+mysql) C# 位运算详解 c# 交错数组 c# 数组协变 C# 添加Excel表单控件(Form Controls) C#串口通信程序
C#中缓存的使用 缓存的概念及优缺点在这里就不多做介绍,主要介绍一下使用的方法. 1.在ASP.NET中页面缓存的使用方法简单,只需要在aspx页的顶部加上一句声明即可: <%@ Outp ...
- opencv入门系列教学(六)图像上的算术运算(加法、融合、按位运算)
0.序言 这一篇博客我们将学习图像的几种算术运算,例如加法,减法,按位运算等. 1.图像加法 我们可以通过OpenCV函数 cv.add() 或仅通过numpy操作 res=img1+img2 res ...
- LeetCode解题中位运算的运用
位运算是我最近才开始重视的东西,因为在LeetCode上面刷题的时候发现很多题目使用位运算会快很多.位运算的使用包含着许多技巧(详细可以参考http://blog.csdn.net/zmazon/ar ...
- 欧几里得算法(及扩展)&&快速幂(二分+位运算)
最近在二中苦逼地上课,天天听数论(当然听不懂) 但是,简单的还是懂一点的 1.欧几里得算法 说得这么高级干什么,gcd入门一个月的人都会吧,还需要BB? 证明可参照其他博客(不会),主要就是gcd(a ...
- 深入V8引擎-枚举+位运算实现参数配置
不知不觉都快月底了,看了看上一篇还是6号写的,惭愧惭愧,说好的坚持.为了证明没有偷懒(其实还是沉迷了一会dota2),先上一个图自证清白. 基本上从初始化引擎,到Isolate.handleScope ...
- nyist oj 138 找球号(二)(hash 表+位运算)
找球号(二) 时间限制:1000 ms | 内存限制:65535 KB 难度:5 描写叙述 在某一国度里流行着一种游戏.游戏规则为:现有一堆球中.每一个球上都有一个整数编号i(0<=i< ...
- Java 位运算2-LeetCode 201 Bitwise AND of Numbers Range
在Java位运算总结-leetcode题目博文中总结了Java提供的按位运算操作符,今天又碰到LeetCode中一道按位操作的题目 Given a range [m, n] where 0 <= ...
- 简简单单学会C#位运算
一.理解位运算 要学会位运算,首先要清楚什么是位运算?程序中的所有内容在计算机内存中都是以二进制的形式储存的(即:0或1),位运算就是直接对在内存中的二进制数的每位进行运算操作 二.理解数字进制 上面 ...
- SQL Server时间粒度系列----第8节位运算以及设置日历数据表节假日标志详解
本文目录列表: 1.位运算 2.设置日历数据表节假日标志 3.总结语 4.参考清单列表 位运算 SQL Server支持的按位运算符有三个,分别为:按位与(&).按位或(|).按位异或 ...
随机推荐
- RESTful Web Services初探
RESTful Web Services初探 作者:杜刚 近几年,RESTful Web Services渐渐开始流行,大量用于解决异构系统间的通信问题.很多网站和应用提供的API,都是基于RESTf ...
- web开发以及分布式开发C/S B/S系统结构
分布式开发,由客户端发送请求给服务端,经服务端进行请求处理后返回处理结果(远程方法调用),在客户端发送请求,获取httpclient/okclient对象,传入参数(URL以及其余参数等),发送请求 ...
- SQL Server 自定义聚合函数
说明:本文依据网络转载整理而成,因为时间关系,其中原理暂时并未深入研究,只是整理备份留个记录而已. 目标:在SQL Server中自定义聚合函数,在Group BY语句中 ,不是单纯的SUM和MAX等 ...
- Json与Bean互转,Timestamp类型的问题
Json与Java Bean互相转换时,Bean中的Timestamp字段是无法直接处理的,需要实现两个转换器. DateJsonValueProcessor的作用是Bean转换为Json时将Time ...
- [CSS]多浏览器兼容的垂直居中,兼容多个IE
相信你都是在兼容垂直居中而烦恼,翻阅多个网站总是找不到理想的方法而苦恼,来到这里你的问题解决了!如果对你有帮助请点个赞,谢谢. 多兼容垂直居中,在IE6-9亲自测试并通过 <!doctype h ...
- 新版本eclipse Neon 4.6.1,登录git报401 没有权限
新版本eclipse Neon 4.6.1,登录git报401 没有权限 经过查找原因竟然是新的eclipse需要进行update.比较坑,新版eclipse竟然需要先更新一下才能用! eclipse ...
- c++ stl容器set成员函数介绍及set集合插入,遍历等用法举例
c++ stl集合set介绍 c++ stl集合(Set)是一种包含已排序对象的关联容器.set/multiset会根据待定的排序准则,自动将元素排序.两者不同在于前者不允许元素重复,而后者允许. 1 ...
- Exynos 4412 Uboot源码解析
原文地址:http://www.cnblogs.com/jacklu/p/6226330.html Exynos 4412 Uboot的汇编代码就不贴了,没有的可以私信我. 这是我当时阅读代码时的思维 ...
- select 一直返回0
select设置超时时间后一直返回零,是因为每次select后监听的fd_set都被重置,解决方法就是每次重新设置
- 删除ubuntu后无法进入windows
一天,脑袋一热想装个ubuntu学习学习,结果装的ubuntu版本比较老,没有集成我笔记本的网卡驱动,在ubuntu下上不了网,心想上不了网学习起来不是很不方便,于是就直接在win7下将ubuntu的 ...