按位取反符号
这里说的取反符号指的是~ 而不是! 。 ~ 会对数值进行取反操作。
例如,1的二进制表示为00000000 00000000 00000000 00000001。 ~1 则为11111111 11111111 11111111 11111110,即—— -2。
这里需要注意,实际上-2在计算机中的存储并非为11111111 11111111 11111111 11111110。
注:本文默认数值有32个二进制位。
这里涉及到原码反码和补码相关知识。
在介绍原码反码补码之前,我们需要了解一下机器码相关的知识。
机器码
一个数在计算机中的二进制表示形式, 叫做这个数的机器数。
机器数带符号,一般把二进制为的最高位定为其符号位,最高位为0是为非负数,为1是是负数。
例如2表示为00000000 00000000 00000000 00000010, -3表示为10000000 00000000 00000000 00000011。
真值
机器码对应的真实数值称为真值。
例如机器码10000000 00000000 00000000 00000011 对应的真值为-3,而非2147483651。
原码、反码、补码
原码反码和补码是计算机存储一个数值的编码方式。 只有有符号数才有原码反反码和补码。 在C/C++中,(signed) char、(signed) short、(signed) int、(signed) long、(signed) long long都为有符号类型, 而unsigned char、unsigned short、unsigned int、unsigned long、unsigned long long都为无符号类型。无符号类型相比于相应的有符号类型,有大了约一倍的正数取值范围,但却无法表示负数。
例如:
unsigned int a = -1;
cout << a << endl;
输出为
4294967295
原码
原码就是符号位加上真值的绝对值。
例如: 1表示为00000000 00000000 00000000 00000001。 -1表示为10000000 00000000 00000000 00000001。
反码
非负数和负数的表示方法有所不同。
- 非负数:反码与原码一样。
- 负数:将该负数的原码,符号位保持不变,其余各位进行取反运算。
例如:
1
=
00000000
?
00000000
?
00000000
?
0000000
1
反
码
1 = 00000000\ 00000000\ 00000000\ 00000001_{反码}
1=00000000?00000000?00000000?00000001反码?
?
1
=
11111111
?
11111111
?
11111111
?
1111111
0
反
码
-1 = 11111111\ 11111111\ 11111111\ 11111110_{反码}
?1=11111111?11111111?11111111?11111110反码?
如图所示。
补码
补码在负数与非负数的表示上也有不同。
例如: -1的补码表示为:11111111 11111111 11111111 11111111。 如下图所示。 负数在计算机上是以补码的形式存储的。
C++位取反
~ 常用在条件判断中,例如:
if(~a) cout << "a != -1" << endl;
这个语句相当于:
if(a != -1) cout << "a != -1" << endl;
由上方补码的介绍我们可以得出,-1在计算机中以二进制的形式存储为11111111 11111111 11111111 11111111,即所有位都为1。
而按位取反运算,会将包括符号位在内的每一位进行取反操作,因此~-1 的结果为00000000 00000000 00000000 00000000,即为0。
注:在C/C++的条件判断中,非零即为真。
补充
逻辑取反符号
! 也是C/C++中的“取反符号”,但它的运算过程和按位取反符号~ 并不一样。
! 更准确地说应该是逻辑取反符号,它的效果是将真变成假,将假变成真。
而~ 则是按位进行的取反运算。
更快速地计算
如何快速的知道一个数的进行按位取反后的值是多少呢? 例如 ~5 的值是多少呢?
除了按照其转换规则进行计算外,还有更加简便的方法得出其值。 在取值范围内,有
?
a
=
?
1
?
a
~a = -1 - a
?a=?1?a
注意优先级
按位取反符号在C语言中的优先级为2,在C++中的优先级为3,与自增运算符同一个优先级,优先级较高,在复合运算时需要多加注意。
为什么会有补码
在计算机中,使对两个数实现加法非常简单,但将两个数进行减法运算却并不容易。 有因为
a
?
b
=
a
+
(
?
b
)
a - b = a + (-b)
a?b=a+(?b) 所以可以考虑将减法变成加法进行计算。
但是使用原码进行计算,却也并不容易,需要让计算机辨别到最高位的符号位,这会使得计算变得繁琐,降低计算机的计算速度。
补码正是因此而生的,使用补码表示负数后,当两个数互为相反数,相加结果直接为0,不需要多考虑符号位之类的问题,也避免了繁琐的运算流程降低了计算机的计算效率。
原创不易,感谢支持!
|