二进制、源码、反码、补码,以及位运算

二进制转为十进制

二进制1101.11

1
2
3
4
5
6
7
8
1=1
10=2
100=4
1000=8
10000=16
0.1=2^-1=0.5 (负次方为正次方的倒数)
0.01=2^-2=0.25
1101.11=8+4+0+1+0.5+0.25=13.75

源码、反码、补码

一个有符号定点数的最高位为符号位,0是正,1是负

例如,0000001 就是+1,1000001 就是-1
正数的反码和补码都是和原码相同
负数的反码是将其原码除符号位之外的各位求反

源码

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

[+1]原 = 0000 0001

[-1]原 = 1000 0001

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

[1111 1111 , 0111 1111],即:

[-127 , 127]

原码是人脑最容易理解和计算的表示方式.

反码

反码的表示方法是:正数的反码是其本身;负数的反码是在其原码的基础上, 符号位不变,其余各个位取反。

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

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

可见如果一个反码表示的是负数, 人脑无法直观的看出来它的数值. 通常要将其转换成原码再计算。

补码(即在反码的基础上+1)

补码的表示方法是:正数的补码就是其本身;负数的补码是在其原码的基础上, 符号位不变, 其余各位取反, 最后+1. (即在反码的基础上+1)

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

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

对于负数, 补码表示方式也是人脑无法直观看出其数值的. 通常也需要转换成原码在计算其数值.

为什么有源码、补码、反码

计算十进制的表达式: 1-1=0

1
2
3
1 - 1 = 1 + (-1) =
[00000001]原 + [10000001]原 =
[10000010]原 = -2

为了解决原码做减法的问题, 出现了反码。

1-1=0

1
2
3
4
5
1 - 1 = 1 + (-1)
= [0000 0001]原 + [1000 0001]原
= [0000 0001]反 + [1111 1110]反
= [1111 1111]反 = [1000 0000]原
= -0

-0 没有意义,补码的出现就是解决编码问题

1
2
3
4
5
1-1 = 1 + (-1)
= [0000 0001]原 + [1000 0001]原
= [0000 0001]补 + [1111 1111]补
= [0000 0000]补
=[0000 0000]原

位运算

按位与:两个都是 1 就是 1
9 & 5

1
2
3
1001 = 9
0101 = 5
0001 = 1

按位或: 有一个(允许2个)为 1 就是 1
9 | 5

1
2
3
1001 = 9
0101 = 5
1101 = 13

按位抑或:不一样的就是 1
9 ^ 5

1
2
3
1001 = 9
0101 = 5
1100 = 12

按位同或:一样的就是 1(无论为1还是0)
9 ^ 5

1
2
3
1001 = 9
0101 = 5
0011 = 3

左移运算

左移运算符m<<n表示吧m左移n位。左移n位的时候,最左边的n位将被丢弃,同时在最右边补上n个0.比如:

00001010 << 2 = 00101000

10001010 << 3 = 01010000

右移运算

右移运算符m>>n表示把m右移n位。右移n位的时候,最右边的n位将被丢弃。但右移时处理最左边位的情形要稍微复杂一点。这里要特别注意,如果数字是一个无符号数值,则用0填补最左边的n位。如果数字是一个有符号数值,则用数字的符号位填补最左边的n位。也就是说如果数字原先是一个正数,则右移之后再最左边补n个0;如果数字原先是负数,则右移之后在最左边补n个1.下面是堆两个8位有符号数作右移的例子:

00001010 >> 2 = 00000010

10001010 >> 3 = 11110001

关于移位的运算有这样的等价关系:把整数右移一位和把整数除以2在数学上是等价的。

1
2
a << = 1 ; //a左移一位等效于a = a * 2;
a << = 2 ; //a左移2位等效于a = a * 2的2次方(4);

支持技术分享,觉得有用可以请我喝杯咖啡!