一.机器数和真值

1.机器数

一个数在计算机中的二进制表示形式,叫做这个数的机器数

机器数是带符号的,在计算机用一个数的最高位存放符号,正数为0,负数为1

比如,十进制中的数 +3 ,计算机字长为8位,转换成二进制就是0000 0011.如果是 -3,就是1000 0011

那么,这里的 00000011 和 10000011 就是机器数

2.真值

因为第一位是符号位,所以机器数的形式值就不等于真正的数值

例如上面的有符号数 10000011,其最高位1代表负,其真正数值是 -3 而不是形式值131(10000011转换成十进制等于131

所以,为区别起见,将带符号位的机器数对应的真正数值称为机器数的真值

例如:0000 0001的真值 = +000 0001 = +1,1000 0001的真值 = –000 0001 = –1

二. 原码, 反码, 补码的基础概念和计算方法

在探求为何机器要使用补码之前, 让我们先了解原码, 反码和补码的概念

对于一个数, 计算机要使用一定的编码方式进行存储. 原码, 反码, 补码是机器存储一个具体数字的编码方式

1.原码

原码就是符号位加上真值的绝对值, 即用第一位表示符号, 其余位表示值. 比如如果是8位二进制:

[+1]原=0000 0001 [-1]原=1000 0001

第一位是符号位. 因为第一位是符号位, 所以8位二进制数的取值范围就是:

[1111 1111 , 0111 1111]即[-127 , 127]

2.反码

反码的表示方法是:

正数的反码是其本身

负数的反码是在其原码的基础上, 符号位不变,其余各个位取反

[+1] = [00000001]原 = [00000001]反

[-1] = [10000001]原 = [11111110]反

3.补码

补码的表示方法是:

正数的补码就是其本身

负数的补码是在其原码的基础上, 符号位不变, 其余各位取反, 最后+1. (即在反码的基础上+1)

[+1] = [00000001]原 = [00000001]反 = [00000001]补

[-1] = [10000001]原 = [11111110]反 = [11111111]补

4.为何要使用反码/补码?

1.用于负数减法
计算机操作指令简化,1-1可以表示为 1+(-1),即加法替代减法
1.利用原码计算 -> 1(0000 0001)原 + -1(1000 0001)原 = (1000 0010)原 = -2 计算不符
2.利用反码计算 -> 1(0000 0001)反 + -1(1111 1110)反 = (1111 1111)反 = (1000 0000)原 = -0 计算不符
3.利用补码计算 -> 1(0000 0001)补 + -3(1111 1010)补 = (1111 1011)补 = (1000 0011)原 = -2 计算正确
反码/补码的出现解决了0的符号位和正确计算

三.运算符

1111 1111 1111 1111 1111 1111 1111 1000
1000 0000 0000 0000 0000 0000 0000 0110

1.按位与运算符(&)

1.运算规则

参加运算的两个数据,按二进制位进行”与”运算

运算规则:0&0=0; 0&1=0; 1&0=0; 1&1=1;

即:两位同时为”1”,结果才为”1”,否则为0

例如:

3&4 即0000 0011& 0000 0100 = 0000 0000 因此,3&4的值为0

3&5 即0000 0011& 0000 0101 = 0000 0001 因此,3&5的值为1

注:负数按补码形式参加按位与运算,结果如果是负数也以补码形式呈现

例如:

-3 原码1000 0011 补码 1111 1101

-4 原码1000 0100 补码 1111 1100

-3&-4 即1111 1101&1111 1100 =1111 1100 补码1000 0100 因此-3&-4的值为-4

2.”与运算”的特殊用途

(1)清零.如果想将一个单元清零,即使其全部二进制位为0,只要与一个各位都为零的数值相与,结果为零

例如:n&0=0

(2)取一个数中指定位

方法:取数字n中特定的位,设置一个数字该数的对应位为1,其余位为零,此数与n进行”与运算”可以得到n中的特定位

例如:设n=1110 0010

取n的后4位,用 n & 0000 1111 = 0000 0010 即可

2.按位或运算符(|)

1.运算规则

参加运算的两个对象,按二进制位进行”或”运算

运算规则: 0|0=0; 0|1=1; 1|0=1; 1|1=1;

即:参加运算的两个对象只要有一个为1,其值为1

例如:

3|4 即0000 0011 | 0000 0100 = 0000 0111 因此,3|4的值为7

3|5 即0000 0011 | 0000 0101 = 0000 0111 因此,3|5的值为7

注:负数按补码形式参加按位或运算,结果如果是负数也以补码形式呈现

-3 原码1000 0011 补码 1111 1101

-4 原码1000 0100 补码 1111 1100

-3|-4 即1111 1101|1111 1100 = 1111 1101 补码 1000 0011 因此-3|-4的值为-3

2.”或运算”特殊用途

(1)常用来对一个数据的特定位置为1.

方法:将数字n中特定位置为1,设置一个数字该数的对应位为1,其余位为零.此数与n进行”或运算”可使n中的特定位置为1

例如:将n=1110 0000的后4位置为1,用n| 0000 1111 = 1100 1111即可

3.异或运算符(^)

1.运算规则

参加运算的两个数据,按二进制位进行”异或”运算.

运算规则:0^0=0; 0^1=1; 1^0=1; 1^1=0;

即:参加运算的两个对象,如果两个相应位为”异”(值不同),则该位结果为1,否则为0.

例如:

3^4 即0000 0011 ^ 0000 0100 = 0000 0111 因此,3^4的值为7

3^5 即0000 0011 ^ 0000 0101 = 0000 0110 因此,3^5的值为6

注:负数按补码形式参加按位与运算,结果如果是负数也以补码形式呈现

例如:

-3 原码1000 0011 补码 1111 1101

-4 原码1000 0100 补码 1111 1100

-3^-4 即1111 1101^1111 1100 =0000 0001 因此-3&-4的值为1

2.”异或运算”的特殊用途

(1)对一个数字特定位翻转,设置一个数字该数的对应特定位为1,其余位为零,此数与进行”异或运算”即可

例如:n=1110 1110,使n后4位翻转,用n ^0000 1111 = 1110 0001即可

(2)与0相异或,保留原值,n ^ 00000000 = 1010 1110.

下面重点说一下按位异或,异或其实就是不进位加法,如1+1=0,0+0=0,1+0=1.

异或的几条性质:

1、交换律

2、结合律(即(ab)c == a(bc))

3、对于任何数x,都有xx=0,x0=x

4、自反性: abb=a^0=a;

异或运算最常见于多项式除法,不过它最重要的性质还是自反性

即A XOR B XOR B = A,即对给定的数A,用同样的运算因子(B)作两次异或运算后仍得到A本身

应用举例1:

例如设有A,B两个变量,存储的值分别为a,b,则以下三行表达式将互换他们的值

a=a^b;

b=b^a;

a=a^b;

应用举例2(综合&和^):

一系列数中,除两个数外其他数字都出现过两次,求这两个数字,并且按照从小到大的顺序输出.

  1. int[] a = { 2, 2, 1, 1, 4, 5 };
  2. int x = 0;
  3. for (int i = 0; i < a.length; i++)
  4. x ^= a[i];
  5. int temp = 1;
  6. while ((temp & x) == 0) {
  7. temp <<= 1;
  8. }
  9. int num1 = 0, num2 = 0;
  10. for (int i = 0; i < a.length; i++) {
  11. if ((temp & a[i]) != 0)
  12. num1 ^= a[i];
  13. else
  14. num2 ^= a[i];
  15. }
  16. System.out.println(min(num1, num2) + " " + max(num1, num2));

例如 2 2 1 1 4 5.最后输出的就是4 5

1.得到两个数异或的乘积,就比如上例中x=4^5

2.分离两个数字(找到两个数字不相同的末置位数为分界线)

4.左移运算符(<<)

将一个运算对象的各二进制位全部左移若干位(左边的二进制位丢弃,右边补0)

若左移时舍弃的高位不包含1,则每左移一位,相当于该数乘以2

例如:a = a<< 2将a的二进制位左移2位,右补0

int a=3;

a=a<<2;

0000 0011 -> 0000 1100

即a=12;

5.右移运算符(>>)

将一个数的各二进制位全部右移若干位,正数左补0,负数左补1,右边丢弃

操作数每右移一位,相当于该数除以2

例如:a = a>>2 将a的二进制位右移2位 左补0

int a=24;

a=a>>2;

0001 1000 -> 0000 0110

即a=6

int a=-24

a=a>>2;

1001 1000 -> 1000 0110

即a=-6

6.复合赋值运算符

位运算符与赋值运算符结合,组成新的复合赋值运算符

例如:&= a&=b 相当于 a=a& b

运算规则:和前面讲的复合赋值运算符的运算规则相似

7.不同长度的数据进行位运算

如果两个不同长度的数据进行位运算时,系统会将二者按右端对齐,然后进行位运算

以”与”运算为例说明如下:

以C语言中long型占4个字节,int型占2个字节举例

如果一个long型数据与一个int型数据进行”与”运算,右端对齐后,左边不足的位依下面三种情况补足

(1)如果整型数据为正数,左边补16个0.

(2)如果整型数据为负数,左边补16个1.

(3)如果整形数据为无符号数,左边也补16个0.

例如:long a=123;int b=1;计算a&b

a = 0000 0000 0000 0000 0111 1011

b = 0000 0000 0000 0000 0000 0001

a&b= 0000 0000 0000 0000 0000 0001 =1;

例如:long a=123;int b=-1;计算a&b

a = 0000 0000 0000 0000 0111 1011

b 补码 1111 1111 1111 1111 1111 1111

a&b = 0000 0000 0000 0000 0111 1011

例如:long a=123;unsigned intb=1;计算a&b

a = 0000 0000 0000 0000 0111 1011

b = 0000 0000 0000 0000 0000 0001

a&b= 0000 0000 0000 0000 0000 0001 =1;