按位非 (~)是什么操作?什么是原码、反码、补码?


前言

本文你将会知道JS中的按位非 (~),什么是原码、反码、补码,负数如何在计算机中表示,以及为什么要使用补码。

起因是在复习运算符优先级的时候,发现了按位非(~)。

以下是MDN官方给的示例:

const a = 5;     // 00000000000000000000000000000101
const b = -3;    // 11111111111111111111111111111101

console.log(~a); // 11111111111111111111111111111010
// expected output: -6

console.log(~b); // 00000000000000000000000000000010
// expected output: 2

有点蒙,为什么~a等于-6?真是“基础不牢,地动山摇”,所以有了本文。

我们知道计算机的数据存储是以0和1来表示的。那么为了能完整表示数据,就有了原码、反码、补码。

在计算机中,存储和计算都是以补码来完成的。

下面我们来看一下什么是原码、反码、补码:

1. 原码

负数在二进制中的表示是,最高位是1

如-5:

1000 0101 (原码)

注意,无论8位表示还是多少位,负数最高位都应该是1。

2. 反码

对于正数,反码与原码一致。

对于负数,原码按位取反(最高位不变)。

如-5:

1111 1010 (反码)

3. 补码

对于正数,补码与原码一致。

对于负数,补码要在反码的基础上加1。

如-5:

1111 1011 (补码)

4. 计算

刚刚我们说了计算机的存储和计算都是以补码来完成的。

那么为什么要使用补码?

在论述之前,我们需要知道计算机只要加运算,要通过操作负数来完成减运算。

例如:5 - 5

(1)如果使用原码,有以下结果:

0000 0101 (5原码)

1000 0101 (-5原码)

1000 1010 (-10)

明显不对

(2)如果使用反码,有以下结果:

0000 0101 (5反码)

1111 1010 (-5反码)

1111 1111 (-0反码)

为方便观看,将反码结果转成原码,有1000 0000(-0原码)。似乎结果是正确的?-0不就是0吗?但是我们要知道在计算机中0还有其它表示0000 0000。这样一来就有了两个二进制表示0,这样就乱套了。

(3)如果使用补码,有以下结果:

0000 0101 (5补码)

1111 1011 (-5补码)

10000 0000 (0)

我们讨论的是8位的计算,结果得到了9位,这里就可以直接的舍弃第九位。那么久得到0000 0000,记过为0,完全正确。

所以这就是使用补码的原因。

5. 总结

回到MDN官方示例

const a = 5;     // 00000000000000000000000000000101
console.log(~a); // 11111111111111111111111111111010
// expected output: -6

按位非就是将5的补码的每一位进行反转,从而得到反码。

下面展示一下5的二进制反转后,是如何计算出-6的,切换8位,如下:

1111 1010(补码)

-1得到:

1111 1001(反码)

取反得到最后结果:

1000 0110(原码)

110就是6

参考:

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/Bitwise_NOT

https://www.bilibili.com/video/BV1Y7411t7Fj


文章作者: iamfugui
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 iamfugui !
评论
  目录