原码,反码,补码和移码

Last Updated: 2023-11-29 02:23:42 Wednesday

-- TOC --

反码:one's complementary,补码:two's complementary,基本上所有CPU都用补码来表示负整数(since 1965)!原码自不必说,是什么就是什么。移码用在浮点数的指数部分,the biased exponent。

原码

CPU用原码表示正数,0是0b0,1是0b1,2是0b10,3是0b11......有人说原码的英文是true code,anyway...

反码

反码的英文是one's complementary

反码的计算为:各位取反!

反码的计算对应了一个数学公式,假设B有n个bit位,计算B的反码:

$$(2^n-1)-B$$

反码在计算机中很少被使用,有时只是作为计算的中间形式。

反码也曾经是计算机表达负数的一个方案,但此方案有两个问题:(1)存在+0和-0两种零;(2)实现的计算电路比使用补码多一个计算步骤。

补码

补码的英文是two's complementary

这个名字的由来:一个有n个bit位的数的正负二进制表达相加刚好等于\(2^n\)。

补码的计算:各位取反后加1!(或者减1后各位取反)

补码的计算对应了一个数学公式,假设B有n个bit位,计算B的补码:

$$2^n-B=((2^n-1)-B)+1$$

现代CPU基本全都使用 two's complementary,即用补码来表示负整数!

假设一个4bits的空间,用补码表示所有的数:

N 补码(two's complementary)
-8 1000(*)
-7 1001
-6 1010
-5 1011
-4 1100
-3 1101
-2 1110
-1 1111
0 0000 (+0)
1 0001
2 0010
3 0011
4 0100
5 0101
6 0110
7 0111

负数是补码,正数是原码。或者说,正数的补码就是原码。孤独的最大负数,没有一个正数与之对应!现代CPU全都使用补码的理由很简单:CPU算得快,电路逻辑简单!做减法等同于加上补码,不分正负。

下面的C代码,在小端字节序(little endian)的CPU上,把-3的二进制补码打印出来:

#include <stdio.h>

void getbin(char a, char *bins) {
    static int i = 0;
    unsigned char x = 0x80;
    while (x) {
        if (x & a) bins[i++] = '1';
        else bins[i++] = '0';
        x >>= 1;
    }
}

int main(void) {
    int a = -3;  // show binary of -3
    char *p = (char*)&a;
    char bins[32];
    int i;

    getbin(*(p+3), bins);
    getbin(*(p+2), bins);
    getbin(*(p+1), bins);
    getbin(*(p),   bins);

    for (i=0; i<32; ++i) {
        if ((i%8==0) && (i!=0)) printf(" ");
        printf("%c", bins[i]);
    }
    printf("\n");

    return 0;
}
$ ./t7
11111111 11111111 11111111 11111101

减去一个数,就是加上这个数的补码,比如,2-5=-3

  0010
- 0101
||
\/
  0010
+ 1011 (0101的补码)
---------
  1101 (-3)

比如,2-(-3)=5

  0010
- 1101
||
\/
  0010
+ 0011 (1101的补码)
---------
  0101 (5)

ALU只需要有加法电路即可,ALU的设计也变得非常简单!

两个小技巧

最大负数的

最大负数,没有正数与之对应,下面是常见的坑:

为什么有正整数这个类型?

为什么有unsigned这种类型?似乎只要有补码就行了,已经有正有负了。我理解unsigned类型带来如下好处:

移码

为什么要用移码来表示浮点数中的阶码,即指数部分?

因为阶码可以是正数,也可以是负数,当进行浮点数计算时,必须先对阶,即比较两个数阶码的大小。为了简化比较操作,使操作过程不涉及阶码的符号,对每个阶码都加上一个正常数,称为偏置常数(bias),使所有阶码都转换为正整数,这样,在对浮点数的阶码进行比较的时候,就变成了对两个正整数进行比较,简化了对比操作,加快了计算速度。

浮点数标准:详解IEEE754浮点数

本文链接:https://cs.pynote.net/hd/202112112/

-- EOF --

-- MORE --