1.数字在计算机中的表示
原码、反码和补码都是计算机中用于表示有符号整数的方式。它们的使用旨在解决计算机硬件中的溢出和算术运算问题。
-
原码(Sign-Magnitude): 原码最简单,它的表示方式是用最高位表示符号位,0表示正数,1表示负数,其余位表示数值的绝对值。例如,+5 的原码是 00000101,-5 的原码是 10000101。
-
反码(One's Complement): 反码表示方式在原码的基础上,负数的表示方式稍作修改。对于正数,反码与原码相同。对于负数,反码是将原码中的1变成0,0变成1。例如,+5 的反码仍然是 00000101,-5 的反码是 11111010。
-
补码(Two's Complement): 补码是计算机中最常用的表示方式。它也在原码的基础上稍作修改。对于正数,补码与原码相同。对于负数,补码是将原码中的1变成0,然后在最低位加1。例如,+5 的补码仍然是 00000101,-5 的补码是 11111011。
为什么需要反码和补码以及它们的优点
-
解决0的表示问题: 在原码中,+0 和 -0 有不同的表示,这可能引起混淆。而在反码和补码中,+0 和 -0 都有相同的表示。
-
简化加法运算: 使用补码可以简化加法运算,因为负数的补码加法可以与正数的加法一样进行,而不需要额外的规则。
-
解决溢出问题: 补码在进行加法和减法时,能够自然地处理溢出。当结果超出表示范围时,溢出的位会被丢弃,而不会引发错误。
计算机是如何进行加减运算的
-
加法运算: 在计算机中,加法运算通常使用补码来执行。两个数相加,首先将它们的补码相加,然后检查是否有溢出。如果有溢出,溢出的位将被丢弃。补码的加法可以简化为模运算,其中模是2的n次方,n 是数据类型的位数。结果可能会包含一个溢出标志位,用于指示运算是否溢出。
-
减法运算: 减法运算也使用补码来执行。将被减数的补码与减数的补码相加,然后检查是否有溢出。同样,结果可能会包含一个溢出标志位。这种方式使加法和减法可以使用相同的硬件电路来执行,从而简化了计算机的设计。
原码、反码和补码是计算机中表示有符号整数的方式,它们在解决符号、0表示和溢出问题方面各具优势。补码通常是最常用的表示方式,因为它能够自然地处理加法和减法,并且不需要特殊的规则。
2.位运算规则
位运算是计算机中用于操作二进制位的一组操作符。这些操作符允许您直接操纵数字的二进制表示,通常用于执行一些特定的位级操作。以下是常见的位运算操作和规则:
(1)与、或、异或、取反
-
按位与(AND): 使用
&
操作符执行按位与操作。将两个数字的每个位都与对应位置的位进行比较,如果都为1,则结果位为1,否则为0。java5 & 3 = 1 // 5 的二进制表示:101 // 3 的二进制表示:011 // 按位与的结果:001
-
按位或(OR): 使用
|
操作符执行按位或操作。将两个数字的每个位都与对应位置的位进行比较,如果至少有一个为1,则结果位为1,否则为0。java5 | 3 = 7 // 5 的二进制表示:101 // 3 的二进制表示:011 // 按位或的结果:111
-
按位异或(XOR): 使用
^
操作符执行按位异或操作。将两个数字的每个位都与对应位置的位进行比较,如果两个位不同,则结果位为1,否则为0。java5 ^ 3 = 6 // 5 的二进制表示:101 // 3 的二进制表示:011 // 按位异或的结果:110
-
按位取反(NOT): 使用
~
操作符执行按位取反操作。将数字的每个位都翻转,0 变为1,1 变为0。java~5 = -6 // 注意:取反后可能是负数 // 5 的二进制表示:101 // 按位取反的结果:-110
-
左移(<<)和右移(>>): 使用
<<
操作符执行左移操作,将数字的二进制表示向左移动指定的位数,右侧用0填充。使用>>
操作符执行右移操作,将数字的二进制表示向右移动指定的位数,左侧用符号位(对于有符号数)或0填充。java5 << 2 = 20 // 5 的二进制表示:00000101 // 左移2位的结果:00010100 -5 >> 1 = -3 // -5 的二进制表示:11111011 // 右移1位的结果:11111101
(2)算术移位和逻辑移位
算术移位是一种将数字的二进制位向左或向右移动的操作,但与逻辑移位不同,它在向右移动时保留了符号位。对于正数,算术右移将在左侧填充0,而对于负数,算术右移将在左侧填充1,以保持负数的符号。
- 算术右移:右侧填充0或1,取决于数字的符号。
- 算术左移:左侧填充0。
例子:
正数 5 的二进制表示: 0000 0101
正数 5 的算术右移 1 位: 0000 0010(保留符号位0,右侧填充0)
负数 -5 的二进制表示: 1111 1011
负数 -5 的算术右移 1 位: 1111 1101(保留符号位1,右侧填充1)
逻辑移位(Logical Shift)
逻辑移位是一种将数字的二进制位向左或向右移动的操作,不考虑符号位。逻辑移位在向右或向左移动时都填充0。
- 逻辑右移:右侧填充0。
- 逻辑左移:左侧填充0。
例子:
正数 5 的二进制表示: 0000 0101
正数 5 的逻辑右移 1 位: 0000 0010
负数 -5 的二进制表示: 1111 1011
负数 -5 的逻辑右移 1 位: 0111 1101
总结:
- 算术移位保留符号位并根据符号位进行填充,因此用于数学运算,如除法和乘法。
- 逻辑移位不考虑符号位,始终填充0,通常用于位级操作和数据处理。
(3)位运算常用技巧
-
获取特定位的值:
javanum = 42 # 二进制:101010 bit_2 = (num >> 2) & 1 # 获取第2位的值 print(bit_2) # 输出 1
获取第n位的值:使用右移和按位与操作
((num >> n) & 1)
。这将把第n位的值提取出来(0或1)。 -
设置特定位的值:
设置第n位为1:使用按位或操作
num |= (1 << n)
。 -
清零特定位:
清零第n位:使用按位与和取反操作
num &= ~(1 << n)
。 -
更新特定位的值:
更新第n位的值为1或0:首先清零第n位,然后使用按位或操作设置新值。
这些技巧可以用于对二进制数据进行高效的位级操作,例如对寄存器或标志位进行处理,或者用于位图操作等。在实际编程中,它们通常用于优化性能、节省内存或执行特定的位级任务。