Skip to content

数字在计算机中的表示

基本概念


单位概念


(bit):计算机中最小的数字单位,是“二进制数字”(binary digit)的缩写,它只能取 \(0\)\(1\) 两个值,因此bit被称作“二进制位”。

字节 (byte):\(8\) 个bit组成 \(1\) 个字节(byte),通常也是计算机中最常见的数据大小单位,用于表示 \(8\) 个二进制位的数字或字符。

在计算机中,一个bit指的就是一个二进制位,即最小的数字单位。


二进制表示


例如:

  • 在计算机中,\(7\) 被表示为 \(0000,0111\)。其中,每四位加入 , 便于区分位数。

具体地:

  • \(0000,0111\) 表示的二进制数字是 \(00000111\)
    • 其中,前四位 \(0000\) 表示十进制下的 \(0\),后四位 \(0111\) 表示十进制下的 \(7\)
    • \(0 \times 2^7 + 0 \times 2^6 + 0 \times 2^5 + 0 \times 2^4 + 0 \times 2^3 + 1 \times 2^2 + 1 \times 2^1 + 1 \times 2^0 = 7\)
    • 该表示法将数字 \(7\) 以二进制形式表示,并在前面补上了 \(0\),使其达到了 \(8\) 比特位(bits)的宽度,常常使用这种形式来表示计算机存储的二进制数。

按照上述过程,理论上一个字节(8个bit位)最大表示的数值范围为:

  • \(0000,0000 (0) \sim 1111,1111 (255)\)

原码、反码、补码、移码


由于现实计算中不仅存在正数,还存在负数,因此按照上节中将一个字节中所有位都用来表示数是不合理的。

因此,在一些语言中区分了有符号数无符号数 ,像上节中表示的是无符号数的表示方法。


原码表示法


在使用原码表示法时,二进制数的最高位表示符号位\(0\) 表示正数,\(1\) 表示负数。

以使用 \(8\) 位二进制原码为例,表示 \(-7\) 的二进制原码的步骤如下:

  • \(7\) 的二进制表示转换为 \(8\) 位二进制数的原码: \(0000,0111\)
    • 将该二进制数的符号位取反,即将第一位由“0”变为“1”,得到:\(1000,0111\)

因此,在 \(8\) 位二进制原码表示法中,\(-7\) 的二进制原码为 \(1000,0111\)

按照上述过程,在原码表示下,理论上一个字节(8个bit位)最大表示的数值范围为:

  • \(1111,1111 (-127) \sim 0111,1111 (127)\)

需要注意,这种方式的缺点是正数和负数的加减法需要额外处理符号位,较为复杂。

例如计算:\(-1 + 1 = 1000,0001 + 0000,0001 = 1000,0010 (-2)\)

怎么会是呢???显然是不对的,因此我们又引入了反码。


反码表示法


反码是一种用于计算机中表示负数的二进制数表示法。在反码中:

  • 正数的反码与其原码相同;
    • 而负数则取其对应正数的原码每一位取反(0变为1,1变为0)得到。
    • 反码最高位仍作为符号位,0表示正数,1表示负数。

以使用 \(8\) 位二进制反码为例,表示 \(-7\) 的二进制反码的步骤如下:

  • \(7\) 的二进制表示转换为 \(8\) 位二进制数的原码: \(0000,0111\)
    • 将该二进制数的每一位取反,即将所有的“0”变为“1”,所有的“1”变为“0”,得到:\(1111,1000\)

因此,在 \(8\) 位二进制反码表示法中,\(-7\) 的二进制反码为 \(1111,1000\)

现在计算:\(-1 + 1 = 1111,1110 + 0000,0001 = 1111,1111 (反码)\)

注意 :反码直接计算的结果需要取反才能得到原码,因此对 \(1111,1111\) 的非符号位全部取反得到 \(1000,0000 (-0)\)

显然是对的吧 ,数值是对了,但是出现了“+0”和“-0”的问题,依然不合理,因此我们最终引入了补码。


补码表示法


补码是一种计算机中表示有符号整数的二进制数表示法,也是一种将负数转化为正数的方法。在补码中:

  • 正数的补码与其原码相同;
    • 而负数则为其二进制反码加一。

以使用 \(8\) 位二进制为例,表示 \(-7\) 的二进制补码的步骤如下:

  • \(7\) 的二进制表示转换为 \(8\) 位二进制数的原码: \(0000,0111\)
    • 将每一位取反得到反码:\(1111,1000\),然后末位 \(+1\) 得到:\(1111,1001\)

因此,在 \(8\) 位二进制补码表示法中,\(-7\) 的二进制补码为 \(1111,1001\)。由于 \(-6\) 的二进制补码为 \(1111,1010\),故我们将原本为 \(1111,1000\) 表示为最小值 \(-8\)

按照上述过程,在补码表示下,理论上一个字节(8个bit位)最大表示的数值范围为:

  • \(1000,0000 (-128) \sim 0111,1111 (127)\)

现在计算:\(-1 + 1 = 1111,1111 + 0000,0001 = 1,0000,0000\),其中多出来的一位 \(1\) 由于超过了补码的表示范围,故造成了溢出,最终的计算结果为 \(0000,0000 (0)\)

由此,我们通过补码可以将两个数的减法运算变为加法运算,但是由于符号位的存在,补码很难直接判断真值大小,因此引入移码的概念。


移码表示法


移码是一种为了方便计算二进制浮点数而设计的表示方法:

  • 将每个真值加上一个偏置值,再进行存储;
\[[ x ]_移 = 2^n + x (2^n > x \ge -2^n) \]

举例:

例如 \(x\) 的真值为 \(10100\)

\(x = 10100, [ x ]_移 = 2^5 + 10100 = 1,10100\)(用,分割符号位)

\(-x = -10100, [ -x ]_移 = 2^5 - 10100 = 0,01100\)

\(x = 0\) 时:

\[[ +0 ]_移 = [ -0 ]_移 \]

注意

  • 移码与补码只差一个符号位,符号位取反两者就能相互转换。

证明

  • 正数:\([ x ]_移 = 2^n + x\),相当于在第 \(n\)\(+1\),即在符号位取反。
  • 负数:
\[[ x ]_补 = 2^{n+1} + x = (2^n + x) + 2^n = [ x ]_移 + 2^n $$,也相当于符号位取反。 --- ## IEEE 754 标准 --- ![](https://image.itbaima.net/images/40/image-20230814211439329.png) 根据国际标准 IEEE 754,任意一个二进制浮点数 $V$ 可以表示为如下形式: \]

V = (-1)^S \times M \times 2^E

\[* $(-1)^S$ 表示符号位。当 $S=0$ 时,$V$ 为正数;当 $S=1$ 时,$V$ 为负数。 * $M$ 表示有效数字,其值大于等于 $1$ 小于 $2$。由于其整数部分固定为 $1$,因此在存储时可以省略。例如,尾数为 $1111010$ 时,$M$ 实际上为 $1.111010$。根据 IEEE 754 标准,这个首位的 $1$ 是隐含的,默认存在,因此存储时可以省略,只保存后续部分(如 $1.0101$ 只保存 $0101$),这样可以多存储一位数据。 * $2^E$ 表示指数位,用于移动小数点位置,这也是其被称为浮点数的原因。 例如,对于十进制的 $5.25$,其对应的二进制为 $101.01$,可以表示为 $1.0101 \times 2^2$。因此,$S$ 为 $0$,$M$ 为 $1.0101$,$E$ 为 $2$。 由此可知,浮点类型的数值范围不仅取决于符号和尾数,还取决于其指数。其大致取值范围为: * 单精度:$±3.40282347 \times 10^{38}$ * 双精度:$±1.79769313486231570 \times 10^{308}$ \]