小数在内存中究竟是如何存储的(C语言代码详细讲解 1)

小数在内存中是如何存储的,揭秘诺贝尔奖级别的设计(长篇神文 )

  小数在内存中是以浮点数的形式存储的。浮点数并不是一种数值分类,它和整数、小数、实数等不是一个层面的概念。浮点数是数字(或者说数值)在内存中的一种存储格式,它和定点数是相对的。

C语言使用定点数格式来存储 short、int、long 类型的整数,使用浮点数格式来存储 float、double 类型的小数。整数和小数在内存中的存储格式不一样。

我们在学习C语言时,通常认为浮点数和小数是等价的,并没有严格区分它们的概念,这也并没有影响到我们的学习,原因就是浮点数和小数是绑定在一起的,只有小数才使用浮点格式来存储。

其实,整数和小数可以都使用定点格式来存储,也可以都使用浮点格式来存储,但实际情况却是,C语言使用定点格式存储整数,使用浮点格式存储小数,这是在“数值范围”和“数值精度”两项重要指标之间追求平衡的结果,稍后我会给大家带来深入的剖析。

计算机的设计是一门艺术,很多实用技术都是权衡和妥协的结果。

  浮点数和定点数中的“点”指的就是小数点! 对于整数,可以认为小数点后面都是零,小数部分是否存在并不影响整个数字的值,所以干脆将小数部分省略,只保留整数部分。

定点数

  所谓定点数,就是指小数点的位置是固定的,不会向前或者向后移动。

  假设我们用4个字节(32位)来存储无符号的定点数,并且约定,前16位表示整数部分,后16位表示小数部分,如下图所示:
在这里插入图片描述

精度
  小数部分的最后一位可能是精确数字,也可能是近似数字(由四舍五入、向零舍入等不同方式得到);除此以外,剩余的31位都是精确数字。从二进制的角度看,这种定点格式的小数,最多有 32 位有效数字,但是能保证的是 31 位;也就是说,整体的精度为 31~32 位。
数值范围
  将内存中的所有位(Bit)都置为 1,小数的值最大,为 216 - 2-16,极其接近 216,换算成十进制为 65 536。将内存中最后一位(第32位)置1,其它位都置0,小数的值最小,为2-16。
这里所说的最小值不是 0 值,而是最接近 0 的那个值。
综述
  用定点格式来存储小数,优点是精度高,因为所有的位都用来存储有效数字了,缺点是取值范围太小,不能表示很大或者很小的数字。
反面例子
  在科学计算中,小数的取值范围很大,最大值和最小值的差距有上百个数量级,使用定点数来存储将变得非常困难。

例如,电子的质量为:

0.0000000000000000000000000009 克 = 9 × 10-28 克

太阳的质量为:

2000000000000000000000000000000000 克 = 2 × 1033 克

如果使用定点数,那么只能按照=前面的格式来存储,这将需要很大的一块内存,大到需要几十个字节。

更加科学的方案是按照=后面的指数形式来存储,这样不但节省内存,也非常直观 这种以指数的形式来存储小数的解决方案就叫做浮点数。 浮点数是对定点数的升级和优化,克服了定点数取值范围太小的缺点。

浮点数

  C语言标准规定,小数在内存中以科学计数法的形式来存储,具体形式为:

flt = (-1)sign × mantissa × baseexponent

对各个部分的说明:

1.	flt 是要表示的小数。
2.	sign 用来表示 flt 的正负号,它的取值只能是 0 或 1:取值为 0 表示 flt 是正数,取值为 1 表示 flt 是负数。
3.	base 是基数,或者说进制,它的取值大于等于 2(例如,2 表示二进制、10 表示十进制、16 表示十六进制……)。数学中常见的科学计数法是基于十进制的,例如 6.93 × 1013;计算机中的科学计数法可以基于其它进制,例如 1.001 × 27 就是基于二进制的,它等价于 1001 0000。
4.	mantissa 为尾数,或者说精度,是 base 进制的小数,并且 1 ≤ mantissa < base,这意味着,小数点前面只能有一位数字;
5.	exponent 为指数,是一个整数,可正可负,并且为了直观一般采用十进制表示。

下面我们以 19.625 为例来演示如何将小数转换为浮点格式。

当 base 取值为 10 时,19.625 的浮点形式为:

19.625 = 1.9625 × 101

当 base 取值为 2 时,将 19.625 转换成二进制为 10011.101,用浮点形式来表示为:

19.625 = 10011.101 = 1.0011101×24

19.625 整数部分的二进制形式为:
19 = 1×24 + 0×23 + 0×22 + 1×21 + 1×20 = 10011
小数部分的二进制形式为:
0.625 = 1×2-1 + 0×2-2 + 1×2-3 = 101
将整数部分和小数部分合并在一起:
19.625 = 10011.101

可以看出,当基数(进制)base 确定以后,指数
exponent 实际上就成了小数点的移动位数:

1.	exponent 大于零,mantissa 中的小数点右移 exponent 位即可还原小数的值;
2.	exponent 小于零,mantissa 中的小数点左移 exponent 位即可还原小数的值。

换句话说,将小数转换成浮点格式后,小数点的位置发生了浮动(移动),并且浮动的位数和方向由 exponent 决定,所以我们将这种表示小数的方式称为浮点数。

猜你喜欢

转载自blog.csdn.net/qq_43515862/article/details/108797251