按位取反运算符与补码

Posted zhouyijoe

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了按位取反运算符与补码相关的知识,希望对你有一定的参考价值。

  记得我第一次学C语言时,我并不了解补码,于是我曾经以为对5(二进制表示:101)按位取反得到的是2(二进制表示:010)。有一次我做了个实验,我把~5的运算结果输出到控制台,结果发现是-6!当时我还感到很惊讶:为什么一个正数按位取反后会得到负数!?然后通过百度,我才了解到了补码,才明白这是怎么一回事。

 

  首先,计算机以二进制形式存储正整数时是不会省略高位的0的(这是我当时误解的一个地方)。在C语言中,如果一个整数是char类型的话,那么计算机就会用8个二进制位(一个字节)来存储这个整数。比如,5在内存中不会表示为101,而是表示为00000101。所以如果对5按位取反,得到的二进制串实际上应该是11111010。但是11111010好像并不等于-6啊?不,在计算机中,仅仅用我们过去对二进制数的理解去解读二进制串是不行的。我们应该用新的方法去解读计算机中的二进制串。

 

  为了了解计算机是如何用二进制串来表示整数的,我们需要了解补码的概念。如果一个二进制串是补码的话,那么这个二进制串的最高位(也就是从左往右数第一位)被称为该补码的“符号位”。比如补码00000101的符号位就是0。补码的符号位上的数字决定了补码表示的是正整数还是负整数。当补码的最高位为0时,补码表示的是正整数,这时候我们就要忽略最高位的0,把剩余的位直接转换成十进制正整数,就得到了该补码表示的正整数。比如补码00000101,去掉最高位后得到0000101,把剩余的位直接转换为十进制数得到5,所以补码00000101表示的正整数是5。当补码的最高位为1时,补码表示的是负整数,这时候我们首先要将这个补码上所有的位取反,然后让取反后得到的二进制串加1,得到一个符号位为0的补码,这个符号位为0的补码所表示的正整数就是原补码表示的负整数的绝对值。所以我们按照之前解读表示正整数的补码的方法来得到取反加一后得到的补码表示的正整数,然后在这个正整数前面加上一个负号,就得到了原补码表示的负整数。例如,补码11111001,每个位取反后得到00000110,加1后得到00000111,补码00000111表示的正整数是7,在7前面加上负号得到-7,于是补码11111001表示的负整数就是-7。我们规定一个所有位上全为0的补码表示的整数是0。

 

  了解了补码的概念后,我们就可以解释之前为什么对一个正数按位取反后得到的是负数了。因为一个正数的补码的符号位是0,取反后其符号位为1,所以就变成了负数。

 

  根据补码的性质,我们可以得到一个公式,从而快速算出一个数按位取反后得到的结果:~x = -(x + 1)。例如,5按位取反就是~5 = - (5 + 1) = -6。-4按位取反就是~-4 = -(-4 + 1) = 3。

 

  我们粗略地推导一下这个公式:

  当x为正数时,设x取反得到的结果为y,则y必然是一个负数。我们对y取反,得到x,x加上1就是x + 1,由此可知y的绝对值等于x + 1,故y = -(x + 1),即~x = -(x + 1)。

  当x为负数时,设x取反得到的结果为y,则y必然是一个正数。我们对x取反,得到y,y加上1就是y + 1,故x的绝对值为y + 1,x = -(y + 1) → y = -(x + 1),即~x = -(x + 1)。

  0取反后得到-1,也符合公式~x = -(x + 1)。

以上是关于按位取反运算符与补码的主要内容,如果未能解决你的问题,请参考以下文章

复习一个小知识点(反码与按位取反)

位运算符,原码反码补码

知道 补码,如何 计算 原码

Java笔记:位运算

原码反码补码之间的快速转换和简单运算

c++中的位运算计算问题