原码
也叫【符号 - 绝对值】码
最高位0表示正,1表示负,其余二进制位是该数字的绝对值的二进制位
如果是8位二进制,+1的原码是0000 0001,-1的原码是1000 0001
尽管原码简单易懂,但加减运算复杂、存在加减乘除四种运算从而增加了CPU的复杂度、零的表示不唯一(1000 0000或者0000 0000),因此没在计算机中应用
反码
正数的反码是其本身,负数的反码是在其原码的基础上,符号位不变,其余各个位取反
如8位情况下:
+1:原码0000 0001,反码:0000 0001
-1:原码1000 0001,反码:1111 1110
反码运算不便,也没有在计算机中应用
移码
移码表示数值平移n位,n称为移码量
移码主要用于浮点数的阶码的存储
补码(应用在计算机中,用于解决整数的存储)
正数的补码就是其本身,负数的补码是在其原码的基础上,符号位不变,其余各位取反,最后+1(即在反码的基础上+1)
+1的原码是0000 0001,反码是0000 0001,补码是0000 0001
-1的原码是1000 0001,反码是1111 1110,补码是1111 1111
已知十进制求二进制补码:
-
求正整数的二进制:除2取余,直至商为零,余数倒着排序
-
求负整数的二进制:先求与该负数相对应的正整数的二进制代码(记得正整数符号位是0),然后所有位取反,末尾加1,不够位数时左边补1
以-1为例(8位数):
先求出-1相对应的正整数(也就是+1)的二进制代码:0000 0001
然后所有位取反:1111 1110
末尾加1:1111 1111
-
求零的二进制:全是零
已知二进制补码求十进制
-
如果首位是0,则表明是正整数,按普通方法来求
-
如果首位是1,则表明是负数。先将所有位取反,末尾加1,所得数字就是该负数的绝对值
以100 1010为例:
先将所有位取反:011 0101
末尾加1:011 0110,转换为10进制是:54
这个54是绝对值,因此100 1010转为十进制是-54
如果在8位的情况下,其实也一样:
100 1010下的8位完整的是:1100 1010(左边补1)
1100 1010取反:0011 0101
末尾加1:0011 0110,转换为10进制是:54
这个54是绝对值,因此8位下的100 1010转为十进制是-54
如果在32位(也就是常说的4个字节,
int
类型)的情况:100 1010下的32位,要先在前面补29个1:即1111 1111 1111 1111 1111 1111 1111 1100 1010
取反:0000 0000 0000 0000 0000 0000 0000 0011 0101
末尾加1:0000 0000 0000 0000 0000 0000 0000 0011 0110,转换为10进制是:54
这个54是绝对值,因此32位下的100 1010转为十进制是-54
-
如果全是0,则对应的十进制数就是0
(0000 0000)2 = (0)10
(0000 0001)2 = (1)10
(0000 0002)2 = (2)10
…
(0111 1111)2 = (127)10
(1000 0000)2 = (-128)10
(1000 0001)2 = (-127)10
(1000 0002)2 = (-126)10
…
(1111 1111)2 = (-1)10
值得注意的是:(1000 0000)2,它比较特殊
如果直接去看1000 0000,最高位是1,是负数,其它为0,所以认为这个是十进制下的-0,这也是原码和反码会出现的问题,因为0会出现两种不同的表达方法:(0000 0000)或者(1000 0000)
因此才诞生出补码
按照上述二进制补码转换为十进制的方法:
先取反:0111 1111
然后加一:1000 0000,转换为10进制是128
128是绝对值,因此1000 0000(不要与上面加一后的1000 0000弄混)的十进制是-128使用原码,则8位的取值范围是[1111 1111 , 0111 1111],即[-127 , 127]
使用补码,则8位的取值范围是[1000 0000 , 0111 1111],即[-128 , 127]
int a = 0x80;
printf("%d\n",a);//输出结果:128
char b = 0x80;
printf("%d\n",b);//输出结果:-128
0x80转成二进制是:1000 0000
对于变量a
来说,由于它是整型数,所以占4个字节,也就是32位。32位下的0x80是:0000 0000 0000 0000 0000 0000 1000 0000,最高位的是0,代表正数,因此以十进制输出a的结果就是128
对于变量b
来说,由于它是字符型,字符型占1个字节,也就是8位。8位下的0x80是:1000 0000。最高位是1,因此它就这么变成了负数,以十进制输出b的记过就是-128
还有一点要注意的是,尽管上面的代码段在gcc编译器下编译没有警告,但在一些编译器上上面的代码会有警告,比如语句char b=0x80
可能会有有警告:truncation from 'const int' to 'char'
,这是说0x80
是整形常量,把整型常量赋给char
类型,可能会丢失数据,因为char
是1个字节,int
是4个字节,把占4个字节的数据赋给占1个字节的变量,前面3个高位字节就会丢失