被程序员忽视的位运算
在博客园潜水好久了,今天兴致高昂的想写一篇博客,写的内容就是最近刚刚弄懂的关于位运算的题目。可能对那些老鸟老说这些是在基础不过的东西了,但是我相信还是有很多的博客需要了解并掌握这个基础的。
做题目前首先需要掌握的知识:
~ 取反运算符,如果运算位为1取反后则变为0,如果运算为为0取反后则为1
& 与运算符,当运算的两个数同时为1时,则与运算的结果才为1,否则为0
| 或运算符,当运算的两个数只要有一个1时,则或运算的结果为1,否则为0.
^ 异或运算符,当两个运算位不同时为1,相同时是0
>> 右移运算符
<< 左移运算符
在内存中的运算都是以补码的形式存在的。
正数的原码、反码、补码相同。
负数的原码:最高为符号为0代表正、1代表负。后面的数为整数转换后的二进制数。
负数的反码:除符号为以外的位进行取反,1变为0,0变为1
负数的补码:负数的反码+1
这里举个简单的负数的例子,这里以整数占4个字节为例:
整数-5
(-5)10 的原码为:(10000000 00000000 00000000 00000101)2
(-5)10 的反码为:(11111111 11111111 11111111 11111010)2
(-5)10 的补码为:(11111111 11111111 11111111 11111011)2
算术右移:低位溢出,符号位不变,并用符号位补溢出的高位。
算术左右:符号位不变,低位补0
基础知识就这么点了。不过这里没有必要死记,在一边做题目的时候,一边在看定义,这样对于理解会很有帮助的。
题目1
~2
因为:2为正数,所以2的原码等于2的反码等于2的补码
因为计算中的运算都是以补码的形式存在的。所以我们需要2的补码为(00000000 00000000 00000000 00000010)2
对2的补码进行取反运算得到: (11111111 11111111 11111111 11111101)2
此时得到的结论为(~2)的补码为 (11111111 11111111 11111111 11111101)2
因为最高位为1,所以是负数看,负数的补码等于负数的反码+1
所以又可以得到了(~2)的反码为 (11111111 11111111 11111111 11111100)2
根据反码又可以得到(~2)的原码为 (10000000 00000000 00000000 00000011)2
最后我们把二进制数转化为十进制数-3.
所以~2=-3
题目2
2&3 2|3
因为2、3都为正数,所以2、3的原码等于反码等于补码。
即(2)10的原码、反码、补码为 (00000000 00000000 00000000 00000010)2
(3)10的原码、反码、补码为 (00000000 00000000 00000000 00000011)2
紧接着我们开始与运算
00000000 00000000 00000000 00000010
& 00000000 00000000 00000000 00000011
00000000 00000000 00000000 00000010
在接着我们开始或运算
00000000 00000000 00000000 00000010
| 00000000 00000000 00000000 00000011
00000000 00000000 00000000 00000011
这与、或运算的结果为补码,我们还需要进行转化成原码。
因为最高为0(符号位),所以表示整数。
即原码等于反码等于补码。
所以2&3的原码用二进制表示为 00000000 00000000 00000000 00000010
转化成十进制为2
2|3的原码用二进制表示为 00000000 00000000 00000000 00000011
转化成十进制为3
题目3
13&7
同样我们可以从题目中知道13、7都是正数,所以正数的原码等于反码等于补码。
即(13)10的原码等于反码等于补码为 (00000000 00000000 00000000 00001101)2
(7)10的原码等于反码等于补码为 (00000000 00000000 00000000 00000111)2
最后我们在脑子里模拟在内存中的运算:
00000000 00000000 00000000 00001101
& 00000000 00000000 00000000 00000111
00000000 00000000 00000000 00000101
从结果中我们可以看出补码的最高位符号位为0表示正数。
所以(13&7)10的原码等于 (00000000 00000000 00000000 000000101)2
转化成十进制数为5
题目4
5|4
同样我们可以从题目中知道5、4都是正数,所以正数的原码等于反码等于补码。
即(5)10的原码等于反码等于补码为 (00000000 00000000 00000000 00000101)2
(4)10的原码等于反码等于补码为 (00000000 00000000 00000000 00000100)2
最后我们在脑子里模拟在内存中的运算:
00000000 00000000 00000000 00000101
| 00000000 00000000 00000000 00000100
00000000 00000000 00000000 00000101
从结果中我们可以看出补码的最高位符号位为0表示正数。
所以(5|4)10的原码等于 (00000000 00000000 00000000 000000101)2
转化成十进制数为5
整数相对而言还是相对简单得,接着我们在来看几个负数的题目。
题目5
(~-5)
首先我们可以知道-5是负数
所以我们要先转化成原码
(-5)10的原码为 (10000000 00000000 00000000 00000101)2
在转化成为反码
(-5)10的反码为 (11111111 11111111 11111111 11111010)2
在转化成为补码
(-5)10的补码为 (11111111 11111111 11111111 11111011)2
得到了补码我们可以开始取反运算了:
(~-5)10的补码为 (00000000 00000000 00000000 00000100)2
这里可以看到最高为符号位为0,所以表示的是整数。
正数的原码等于反码等于补码。
所以(~-5)10的原码为 (00000000 00000000 00000000 00000100)2
最后(~-5)=4
紧接着我们来看左移运算符和右移运算符。
题目6
-1>>2
因为是-1是负数,所有我们先通过一系列的转化得到他的补码。
(-1)10 的原码为: (10000000 00000000 00000000 00000001)2
(-1)10 的反码为: (11111111 11111111 11111111 11111110)2
(-1)10 的补码为: (11111111 11111111 11111111 11111111)2
紧接着我们开始右移运算,溢出位用符号位来补。右移2位得到
(-1>>2)10 的补码为: (11111111 11111111 11111111 11111111)2
因为符号位为1,所以是负数,我们接着算出反码,原码。
(-1>>2)10 的反码为: (11111111 11111111 11111111 11111110)2
(-1>>2)10 的原码为: (10000000 00000000 00000000 00000001)2
所有-1>>2=-1
-1<<2
我直接用上面的到的
(-1)10 的补码为: (11111111 11111111 11111111 11111111)2
紧接着我们在对他进行左移,低位用0补。左移两位得到的结果是
(-1<<2)10 的补码为: (11111111 11111111 11111111 11111100)2
因为符号位为1,所以是负数,我们接着算出反码,原码。
(-1<<2)10 的反码为: (11111111 11111111 11111111 11111011)2
(-1>>2)10 的原码为: (10000000 00000000 00000000 00000100)2
所有-1<<2=-4
题目7
1>>2
因为1是正数,所有原码等于反码等于补码,即
(1)10 的原码等于反码等于补码为 (00000000 00000000 00000000 00000001)2
紧接着我们开始右移运算,
(1>>2)10 的补码为 (00000000 00000000 00000000 00000000)2
因为符号位为0,所有原码等于反码等于
补码为 (00000000 00000000 00000000 00000000)2
所有1>>2=0
1<<2
因为1是正数,所有原码等于反码等于补码,即
(1)10 的原码等于反码等于补码为 (00000000 00000000 00000000 00000001)2
紧接着我们开始右移运算,
(1>>2)10 的补码为 (00000000 00000000 00000000 00000100)2
因为符号位为0,所有原码等于反码等于
补码为 (00000000 00000000 00000000 00000100)2
所有1<<2=4
题目8
-3^3
首先-3的为负数,所以
(-3)10 的原码为 (10000000 00000000 00000000 00000011)2
(-3)10 的反码为 (11111111 11111111 11111111 11111100)2
(-3)10 的原码为 (11111111 11111111 11111111 11111101)2
在因为3为正数则
(3)10 的原码等于反码等于补码为 (00000000 00000000 00000000 00000011)2
紧接着我们开始异或运算
11111111 11111111 11111111 11111101
^ 00000000 00000000 00000000 00000011
11111111 11111111 11111111 11111110
(-3^3) 10 的补码为 (11111111 11111111 11111111 11111110)2
因为符号位为1,所有是负数,所有
(-3^3) 10 的反码为 (11111111 11111111 11111111 11111101)2
(-3^3) 10 的原码为 (10000000 00000000 00000000 00000010)2
所有(-3^3)=-2
题目暂时就先这么多,因为我们要学会举一反三的思想。当然上面只不过是我们的理论知识,但是我们程序员需要有一种用代码检验真理的思想,我这里检验的代码用的是php,因为他的整型都是有符号的。
下面附上php代码
/*运行环境Win7 64位旗舰版 *服务器IIS7.5 *代码语言PHP *编写日期2012-5-31 *编写人:JimmyWu * */ <html> <head> <title>位运算练习</title> <meta http-equiv="content-type" content="text/html;charset=utf-8" /> </head> <body> <?php echo '整形的长度'.PHP_INT_SIZE.'<br />'; //位运算 echo '~2='.(~2).'<br />'; echo '2&3='.(2&3).'<br />'; echo '2|3='.(2|3).'<br />'; echo '~-5='.(~-5).'<br />'; echo '13&7='.(13&7).'<br />'; echo '5|4='.(5|4).'<br />'; echo '-3^3='.(-3^3).'<br />'; echo '-1>>2 = '.(-1>>2).'<br />'; echo '1>>2 = '.(1>>2).'<br />'; echo '-1<<2 = '.(-1<<2).'<br />'; echo '1<<2 = '.(1<<2).'<br />'; ?> </body> </html>
如果不对请指出并给我留言。最后欢迎关注我,也欢迎技术上的交流。
Stallman 先生认为最大的快乐是让自己发展的软件让大家来使用了!