Home
updated:

反码与补码


反码与补码都用于表示有符号数。 反码的定义如下:

B2O_w(x)x_w1(2w11)+_i=0w2x_i2iB2O\_{w}(\vec{x}) \doteq -x\_{w-1}(2^{w-1} - 1) + \sum\_{i = 0}^{w-2}x\_i2^i

补码的定义如下:

B2T_w(x)x_w12w1+_i=0w2x_i2iB2T\_{w}(\vec{x}) \doteq -x\_{w-1}2^{w-1} + \sum\_{i = 0}^{w-2}x\_i2^i

从定义可以看到,无论是反码还是补码,负数的最高有效位总为1。以占2个字节的short类型为例,用反码表示时有: 最小值: 1000 0000 0000 0000, 即-32767 最大值: 0111 1111 1111 1111, 即32767 可以看到最大和最小值是对称的,而反码能表示的16位数据一共有2162^{16}种,显然是一个偶数,这意味着这样的编码方式有两个0,分别是0000 0000 0000 0000和1111 1111 1111 1111。为了解决这种问题,可以使用补码,补码只有一个零,在反码中表示0的1111 1111 1111 1111在补码中表示-1,总体上补码相当于将反码的负数部分向负半轴方向平移了一位,其最小值1000 0000 0000 0000表示-32768. 例子

Decimal34453445Onescomplement00001101011101011111001010001010Twoscomplement00001101011101011111001010001011\begin{array}{ccc} \hline Decimal & 3445 & -3445 \\ \hline Ones' complement & 0000 1101 0111 0101 & 1111 0010 1000 1010 \\ \hline Twos' complement & 0000 1101 0111 0101 & 1111 0010 1000 1011 \\ \hline \end{array}

可以看到,反码正如其名,只需将原正数数按位取反即可得到其相反数。而补码因为最高位的权重比正数最大值多了一,在按位取反的基础上需要在最低位再加上一来抵消偏移量才能得到原数的相反数。对w位的二进制正数x,需要用2wx2^w - x来计算其补码。

测试中用到代码如下:

//main.c
#include <stdio.h>
#include <limits.h>
#include "bitctrl.h"
int main(int argc, const char \* argv\[\]) {
    int a = -13;
    bitsshow(&a);
    a = 13;
    bitsshow(&a);
    return 0;
}
//bitctrl.h
#ifndef bitctrl\_h
#define bitctrl\_h
#define INT\_LEN 32
#define SHORT\_LEN 16
char bitview(int \*, int);
void bitchange(int \*, int, char);
void bitsshow(int \*);
char bitview(int \*src, int pos) //src是指向数据位置的指针,pos是偏移量,从一开始计数
{
    if (pos <= 4) {
        return \*((char \*)src + pos);
    } else {
        printf("Wrong input");
        return -1;
    }
}
void bitchange(int \*src, int pos, char data) //修改位
{
    if (pos <= 4) {
        \*((char \*)src + pos) = data;
    } else {
        printf("Wrong input");
    }
}
void bitsshow(int \*src) { //查看位
    int i = 0;
    int mask\[INT\_LEN\] = {};
    for ( ; i <= INT\_LEN - 1; (\*src) >>= 1, i++) {
        mask\[i\] = \*src & ~(~(unsigned int)0 << 1); //0必须为无符号数
    }
    i--;
    for ( ; i >= 0; --i) {
        printf("%d", mask\[i\]);
        if (i % 4 == 0)
            printf(" ");
    }
    printf("\n");
}
#endif /\* bitctrl\_h \*/

这里有在线编码转换的网站。