signed_number_representation.md

有符号数的表示

有符号数的表示,是指将负数编码表示为二进制形式。目前已知的常见的有符号数的表示有四种:原码、反码、补码、移码。

原码 Signed magnitude representation

原码是通过分配一个符号位表示数的符号,通常是最高位,0代表正数,1代表负数。一个字节8位,使用最高位表示符号位,则数的表示范围是十进制的-127到127。十进制数-43=-(32+8+2+1)使用原码表示1010 1011。

反码 One's complement

反码也是通过一个符号位表示数的符号,通常也是最高位,0代表正数,1代表负数。一个正数的反码与其原码相同,例如十进制数13=8+4+1的1字节原码和反码都是00001101。一个负数的符号位为1,数值位是该负数的相反数的原码数值位互换0和1。因为负数反码的符号位也可以理解成该负数的相反数的原码符号位互换0和1(0>1)。所以,负数的反码即其相反数的原码互换0和1。例如十进制数-13=-(8+4+1)的绝对值为13,13的原码是0000 1101,原码互换0和1就是1111 0010。1字节反码的表示范围仍然是十进制的-127到127。

补码 Two's complement

0与正数的补码与其原码相同,负数的补码等于其反码+1。例如,十进制数-27=-(16+8+2+1),27的原码为0001 1011,则-27反码为1110 0100,-27补码为1110 0101。1字节补码的表示范围是十进制的-128到127。

例子

计算43-13, 43的补码等于原码0010 1011,-13的补码等于反码1111 0010加0000 0001即1111 0011。0010 1011 + 1111 0011 = 0001 1110。若某数补码为0001 1110,其原码等于补码,该数为十进制16+8+4+2=30。

计算-13-27,-13的补码即1111 0011,-27的补码即1110 0101。 1111 0011 + 1110 0101 = 1101 1000。若某数补码为1101 1000,其反码为1101 0111,其原码为0010 1000,该数为十进制-(32+8)=-40。

补码原理

这个补码的原理真的搞死我了。

模算数

模算数就是一种整数算术系统,时钟就是一个典型例子。十二小时制的时钟,不能表示大于12或小于1的钟点(整数)。例如,7点再过8小时,时钟指向3点而不是15点。这就是模12的模算术系统。它有什么好处呢?那就是可以利用同余关系简化运算。在模算术系统中,a与b的加减乘法运算,其结果与对应a的同余a’与b的同余b‘的相等。例如,7+8=-5+8=3,其中7与-5关于12同余。

补码回顾

回顾下1000 0000在二进制编码表示128,在补码表示-128,128与-128关于模256同余。补码本质就是把128255的编码映射到其在-128-1的对应同余上。计算法则沿用的是非负范围的二进制编码运算,但是整个编码的值域移动了。举个例子加深印象,假设补码使用1000 0000表示128,而不是-128。计算128-127=1000 0000+1000 0001 =0000 0001(最高位溢出)。有没有感觉?所以改变的只是我们约定的编码的值域。对负数求补码的过程,求反码再加1。例如-127,其相反数127的原码0111 1111,-127的反码1000 0000。注意0111 1111+1000 0000=1111 1111即255,可得-127=255-127+1=129。所以负数的补码,就是求其对应的正同余的原码。