被程序员忽视的位运算

  在博客园潜水好久了,今天兴致高昂的想写一篇博客,写的内容就是最近刚刚弄懂的关于位运算的题目。可能对那些老鸟老说这些是在基础不过的东西了,但是我相信还是有很多的博客需要了解并掌握这个基础的。

做题目前首先需要掌握的知识:

~           取反运算符,如果运算位为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)

  最后我们在脑子里模拟在内存中的运算:

                        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)

  最后我们在脑子里模拟在内存中的运算:

                        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 先生认为最大的快乐是让自己发展的软件让大家来使用了!

原文地址:https://www.cnblogs.com/Jimmy009/p/2528992.html