补码与反码(附运算优先级)

发布时间 2023-09-08 10:54:23作者: NBest

2023-08-30 16:56:00

我们都知道在计算机存储的时候,有符号的数都会用最高位作为符号位。

参考:什么是原码、反码和补码

原码

就是正常的二进制数,把最高位改成符号位(0为正数,1为负数)。

正数计算不会有问题:

5+2:

 0 0 0 0 0 1 0 1
+        0 0 1 0
-----------------
 0 0 0 0 0 1 1 1

=7

反码

正数的反码就是原码,负数的反码是把原码中除符号位以外的所有位(数值位)取反

为什么要引入反码呢?因为计算机中直接用原码加减只能解决正数加减,而带负数加减如果用原码就会出现很大的错误,如:

-56-1:原码

 1 0 1 1 1 0 0 0
-              1
-----------------
 1 0 1 1 0 1 1 1

=-55???

那如果我们用反码运算:

-56-1:反码

  1 1 0 0 0 1 1 1
 -              1
-----------------
  1 1 0 0 0 1 1 0

=-57

没有任何问题。

补码

正数的补码是原码,负数的补码是反码加 1。

为什么要搞出一个奇奇怪怪的补码?

因为用反码做负数跨 0 运输也会错。

如:-3+5:反码

 1 1 1 1 1 1 0 0
+        0 1 0 1  
-----------------
 0 0 0 0 0 0 0 1 

=1??

用补码:

 1 1 1 1 1 1 0 1
+        0 1 0 1
----------------- 
 0 0 0 0 0 0 1 0

正确。

不仅如此,如果用反码,0的表示就有了歧义,+0反码00000000,-0反码11111111,而且还浪费一个位置,但是用补码则不然。这也是为什么 int 的范围是 \([-2147483648,2147483647]\),负数可以多表示一个,而 \(-2147483648\) 在 4 字节整型中并没有原码和反码,只有补码。

补码变原码:

  • 先减1再取反
  • 先取反再加1

个人认为第二个好记。

注:

进行位运算时用的都是补码,所以 OIer 们判断是不是 \(-1\) 常用 ~p,如果是 -1 的话,结果就是0,也是因为 -1 的补码是全 1。

c++运算符优先级归纳