• 微信号
  • 微信号
您当前的位置:首页 > 学海无涯 > 茑语花香>C语言小数在内存中是如何存储的

C语言小数在内存中是如何存储的

孤峰 孤峰家 2023-06-18 86人阅读

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

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

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

假设我们用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 × **ntissa × base^exponent

对各个部分的说明=

flt 是要表示的小数。

sign 用来表示 flt 的正负号=它的取值只能是 0 或 1=取值为 0 表示 flt 是正数=取值为 1 表示 flt 是负数。

base 是基数=或者说进制=它的取值大于等于 2=例如=2 表示二进制、10 表示十进制、16 表示十六进制……=。

**ntissa 是 base 进制的小数=并且 1 ≤ **ntissa = base=这意味着=小数点前面只能有一位数字。

exponent 为指数=是一个整数=可正可负=并且为了直观一般采用十进制表示。

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

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

19.625 = 1.9625 × 10^1

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

19.625 = 10011.101 = 1.0011101×24

二进制形式的浮点数的存储

虽然C语言标准没有规定 base 使用哪种进制=但是在实际应用中=各种编译器都将 base 实现为二进制=这样不仅贴近计算机硬件=任何数据在计算机底层都以二进制形式表示==还能减少转换次数。

仍然以 19.625 为例=将它转换成二进制形式的浮点数格式=

19.625 = 1.0011101×24

此时符号 sign 为 0=尾数 **ntissa 为 1.0011101=指数 exponent 为 4。

1) 符号的存储

符号的存储很容易=就像存储 short、int 等普通整数一样=单独分配出一个位=Bit=来=用 0 表示正数=用 1 表示负数。对于 19.625=这一位的值是 0。

2) 尾数的存储

当采用二进制形式后=尾数部分的取值范围为 1 ≤ **ntissa = 2=这意味着=尾数的整数部分一定为 1=是一个恒定的值=这样就无需在内存中提现出来=可以将其直接截掉=只要把小数点后面的二进制数字放入内存中即可。对于 1.0011101=就是把 0011101 放入内存。

我们不妨将真实的尾数命名为 **ntissa=将内存中存储的尾数命名为 **nt=那么它们之间的关系为=

**ntissa = 1.**nt

如果 base 采用其它进制=那么尾数的整数部分就不是固定的=它有多种取值的可能=以十进制为例=尾数的整数部分可能是 1~9 之间的任何一个值=这样一来尾数的整数部分就不能省略了=必须在内存中体现出来。而将 base 设置为二进制就可以节省掉一个位=Bit=的内存=这也算是采用二进制的一点点优势。

3) 指数的存储

指数是一个整数=并且有正负之分=不但需要存储它的值=还得能区分出正负号来。

short、int、long 等类型的整数在内存中的存储采用的是补码加符号位的形式=数值在写入内存之前必须先进行转换=读取以后还要再转换一次。但是为了提高效率=避免繁琐的转换=指数的存储并没有采用补码加符号位的形式=而是设计了一套巧妙的解决方案=稍等我会为您解开谜团。 为二进制浮点数分配内存

C语言中常用的浮点数类型为 float 和 double=float 始终占用 4 个字节=double 始终占用 8 个字节。

下图演示了 float 和 double 的存储格式=

浮点数的内存被分成了三部分=分别用来存储符号 sign、尾数 **ntissa 和指数 exponent =当浮点数的类型确定后=每一部分的位数就是固定的。

总结

与定点数相比=浮点数在精度方面损失不小=但是在取值范围方面增大很多。牺牲精度=换来取值范围=这就是浮点数的整体思想。

转载:感谢您阅览,转载请注明文章出处“来源从小爱孤峰知识网:一个分享知识和生活随笔记录的知识小站”。

链接:C语言小数在内存中是如何存储的http://www.gufeng7.com/niaolang/470.html

联系:如果侵犯了你的权益请来信告知我们删除。邮箱:119882116@qq.com

标签: