计算机对 数 的表示原理

搜索到的答案都是表示方法,在百度会理解为对数,想问大佬们计算机对 数 的表示原理是什么呢,感谢感谢

分为 整数 和 浮点数

一、整数用补码表示

1)定义

【定义】 正数补码 就是它的 原码负数补码 为 它的反码加一

2)举例

  • 1)对于十进制数 37,它的 真值 和 补码 关系如下:
    真值:+ 00000000 00000000 00000000 00100101
    补码:  00000000 00000000 00000000 00100101
    
  • 2)对于十进制数 -37,它的 真值 和 反码 的关系如下:
    真值:- 00000000 00000000 00000000 00100101
    补码:  11111111 11111111 11111111 11011011
    
  • 我们发现,对于负数的情况,反码 减去 真值(注意,这里真值为负数)后,负负得正,转换成二进制位相加正好等于 $1(\underbrace{0...0}_{32})_2$, 即 $2^{32}$,表示成公式如下:$$ [x]_补 - x = 2^{32}$$

    3)公式

  • 因此,通过移项,我们可以得出补码的十进制计算公式如下:

    $$[x]_补 = \begin{cases} x & (0 \le x < 2^{n-1})\ 2^{n} + x & (-2^{n-1} \le x < 0) \end{cases}$$   这里 $x$ 代表真值,而 $n$ 的取值是 $8、16、32、64$,我们通常说的整型int都是 32位 的,本文就以 $n = 32$ 的情况进行阐述;

    4、编码总结

    对于三种编码方式,总结如下:
      1)这三种机器数的最高位均为符号位;
      2)当真值为正数时,原码、反码、补码的表示形式相同,符号位用 "0" 表示,数值部分真值相同;
      3)当真值为负数时,原码、反码、补码的表示形式不同,但是符号位都用 "1" 表示,数值部分:反码是原码的 "按位取反",补码是反码加一;

正数

真值:+ 00000000 00000000 00000000 00100101
原码:  00000000 00000000 00000000 00100101
反码:  00000000 00000000 00000000 00100101
补码:  00000000 00000000 00000000 00100101

负数

真值:- 00000000 00000000 00000000 00100101
原码:  10000000 00000000 00000000 00100101
反码:  11111111 11111111 11111111 11011010
补码:  11111111 11111111 11111111 11011011

二、浮点数的存储

1、科学计数法

  • C语言中,浮点数在内存中是以科学计数法进行存储的,科学计数法是一种指数表示,数学中常见的科学计数法是基于十进制的,例如 $5.2 × 10^{11}$;计算机中的科学计数法可以基于其它进制,例如 $1.11 × 2^7$ 就是基于二进制的,它等价于 $(11100000)_2$。
  • 科学计数法的一般形式如下:
  • $$value = (-1)^{sign} \times fraction \times base^{exponent}$$

      $value$:代表要表示的浮点数;
      $sign$:代表 $value$ 的正负号,它的取值只能是 0 或 1:取值为 0 是正数,取值为 1 是负数;
      $base$:代表基数,或者说进制,它的取值大于等于 2;
      $fraction$:代表尾数,或者说精度,是 $base$ 进制的小数,并且 $1 \le fraction \lt base$,这意味着,小数点前面只能有一位数字;
      $exponent$:代表指数,是一个整数,可正可负,并且为了直观一般采用 十进制 表示。

1)十进制的科学计数法

  • 以 $14.375$ 这个小数为例,根据初中学过的知识,想要把它转换成科学计数法,只要移动小数点的位置。如果小数点左移一位,则指数 $exponent$ 加一;如果小数点右移一位,则指数 $exponent$ 减一;
  • 所以它在十进制下的科学计数法,根据上述公式,计算结果为:
  • $$(14.375)_{10} = 1.4375 \times 10^1$$
  • 其中 $value = 14.375$、$sign = 0$、$base = 10$、$fraction = 1.4375$、$exponent = 1$;
  • 这是我们数学中最常见的科学计数法。

    2)二进制的科学计数法

  • 同样以 $14.375$ 这个小数为例,我们将它转换成二进制,按照两部分进行转换:整数部分和小数部分。
  • 整数部分:整数部分等于 14,不断除 2 取余数,转换成 2 的幂的求和如下:
  • $$(14)_{10} = 1 \times 2^3 + 1 \times 2^2 + 1 \times 2^1 + 0 \times 2^0$$
  • 所以 14 的二进制表示为 $(1110)_2$。
  • 小数部分:小数部分等于 0.375,不断乘 2 取整数部分的值,转换成 2 的幂的求和如下:
  • $$(0.375)_{10} = 0 \times 2^{-1} + 1 \times 2^{-2} +1 \times 2^{-3}$$
  • 所以 0.375 的二进制表示为 $(0.011)_2$
  • 将 整数部分 和 小数部分 相加,得到的就是它的二进制表示:
  • $$(1110.011)_2$$
  • 同样,我们参考十进制科学计数法的表示方式,通过移动小数点的位置,将它表示成二进制的科学计数法,对于这个数,我们需要将它的小数点左移三位。得到:
  • $$(1110.011)_2 = (1.110011)_2 \times 2^3$$
  • 其中 $value = 14.375$、$sign = 0$、$base = 2$、$fraction = (1.110011)_2$、$exponent = 3$;
  • 我们发现,为了表示成科学计数法,小数点的位置发生了浮动,这就是浮点数的由来。

2、浮点数存储概述

  • 计算机中的浮点数表示都是采用二进制的。上面的科学计数法公式中,除了 $base$ 确定是 2 以外,符号位 $sign$、尾数位 $fraction$、指数位 $exponent$ 都是未知数,都需要在内存中体现出来。还是以 $14.375$ 为例,我们来看下它的几个关键数值的存储。

    1)符号的存储

  • 符号位的存储类似存储整型一样,单独分配出一个比特位来,用 0 表示正数,1 表示负数。对于 $14.375$,符号位的值是 0。

    2)尾数的存储

  • 根据科学计数法的定义,尾数部分的取值范围为 $$1 \le fraction \lt 2$$
  • 这代表尾数的整数部分一定为 1,是一个恒定的值,这样就无需在内存中提现出来,可以将其直接截掉,只要把小数点后面的二进制数字放入内存中即可,这个设计可真是省(扣)啊。
  • 对于 $(1.110011)_2$,就是把110011放入内存。我们将内存中存储的尾数命名为 $f$,真正的尾数命名为 $fraction$,则么它们之间的关系为: $$fraction = 1.f$$
  • 这时候,我们就可以发现,如果 $base$ 采用其它进制,那么尾数的整数部分就不是固定的,它有多种取值的可能,以十进制为例,尾数的整数部分可能是 $1 \to 9$ 之间的任何一个值,如此一来,尾数的整数部分就无法省略,必须在内存中表示出来。但是将 $base$ 设置为 2,就可以节省掉一个比特位的内存,这也是采用二进制的优势。

    3)指数的存储

  • 指数是一个整数,并且有正负之分,不但需要存储它的值,还得能区分出正负号来。所以存储时需要考虑到这些。
  • 那么它是参照补码的形式来存储的吗?
  • 答案是否。
  • 指数的存储方式遵循如下步骤:
  • 1)由于floatdouble分配给指数位的比特位不同,所以需要分情况讨论;
  • 2)假设分配给指数的位数为 $n$ 个比特位,那么它能够表示的指数的个数就是 $2^n$;
  • 3)考虑到指数有正负之分,并且我们希望正负指数的个数尽量平均,所以取一半,$2^{n-1}$ 表示负数,$2^{n-1}$ 表示正数。
  • 4)但是,我们发现还有一个 0,需要表示,所以负数的表示范围将就一点,就少了一个数;
  • 5)于是,如果原本的指数位 $x$,实际存储到内存的值就是:$$x + 2^{n-1} - 1$$
  • 接下来,我们拿具体floatdouble的实际位数来举例说明实际内存中的存储方式。

3、浮点数存储内存结构

  • 浮点数的内存分布主要分成了三部分:符号位、指数位、尾数位。浮点数的类型确定后,每一部分的位数就是固定的。浮点数的类型,是指它是float还是double
  • 对于float类型,内存分布如下:

  • 对于double类型,内存分布如下:


  • 1)符号位:只有两种取值:0 或 1,直接放入内存中;
  • 2)指数位:将指数本身的值加上 $2^{n-1}-1$ 转换成 二进制,放入内存中;
  • 3)尾数位:将小数部分放入内存中;
浮点数类型指数位数指数范围尾数位数尾数范围
float$8$$[-2^7+1,2^7]$$23$$[(0)2, (\underbrace{1...1}{23})_2]$
double$11$$[-2^{10}+1,2^{10}]$$52$$[(0)2, (\underbrace{1...1}{52})_2]$

三、参考资料

☀️光天化日学C语言☀️(23)- 整数的存储 | 补码到底有什么用?_英雄哪里出来-CSDN博客 补码到底有什么用? https://blog.csdn.net/WhereIsHeroFrom/article/details/118666729
☀️光天化日学C语言☀️(24)- 浮点数的存储 | 天才般的设计,反正我这么认为_英雄哪里出来-CSDN博客 浮点数的存储,天才般的设计 https://blog.csdn.net/WhereIsHeroFrom/article/details/118690590