博主CSDN主页:Wsys1mple

分类专栏:C语言初阶

gitee代码仓库:Wsys1mple的代码仓库

关注我,持续更新更多学习分享


目录

1. 前言

2. 浮点数存储和整形存储的区别

3. 浮点数存储规则

4. IEEE 754对M的特别规定

5. IEEE 754对E的特别规定

6. 指数E从内存中取出的三种情况

6.1 E不全为0或不全为1✨

6.2E全为0✨

6.3E全为1✨

7. 解释浮点数存储的例子

8. 总结


1. 前言

这里我们将深度剖析浮点型在内存中的存储,希望我的文章对你有所帮助。


常见的浮点数:

3.1415926

2E10(2乘以10的10次方)

浮点数家族包括:float、double、long double 类型。

其中浮点数的表示范围在 float.h 文件中定义

2. 浮点数存储和整形存储的区别

我们先看一个浮点数存储的例子:

int main(){int n = 9;float* pFloat = (float*)&n;printf("n的值为:%d\n", n);//9printf("*pFloat的值为:%f\n", *pFloat);//0.000000*pFloat = 9.0;printf("num的值为:%d\n", n);//1091567616printf("*pFliat的值为:%f\n", *pFloat);//9.000000return 0;}

输出的结果:

为什么是这样呢?num 和 *float 在内存中明明是同一个数,而实际的结果是 *pfloat 的值变成了0.000000,num 的值变成了一个特别大的值,似乎并不符合常理。

我们带着疑问,继续学习以下内容。


3. 浮点数存储规则

根据国际标准IEEE(电气和电子工程协会) 754,任意一个二进制浮点数V可以表示成下面的形式:

  • (-1)^S * M * 2^E
  • (-1)^S表示符号位,当S=0时,V为正数;当S=1时,V是负数。
  • M表示有效数字,并且取值范围是大于等于1,小于2。
  • 2^E表示指数位

举例来说:

十进制的 5.0,写成二进制是 101.0,相当于 1.01 * 2^2。

按照上面的格式,可以得到 S=1,M=1.01,,E=2。

同理,十进制的 -5.0,写成二进制是 -101.0,相当于 -1.01 * 2^2。

按照上面的格式,可以得到 S=0,M=1.01,E=2。

IEEE 754规定:

对于32位的浮点数,最高位是符号位S,接着的8位是指数E,剩下的23位是有效数字M。

对于64位的浮点数,最高位是符号位S,接着的11位是指数E,剩下的52位是有效数字M。

注意:对于所有的浮点数,都可以用 S,E,M表示,因此在内存中存储S,E,M相当于存储了浮点数。


4. IEEE 754对M的特别规定

前面提到有效数字 M 的取值范围是大于等于1,小于2,也就是说 M 可以写成 1.xxxxxx 的形式,其中xxxxxx表示小数部分。

IEEE 754规定,在计算机内部保存M时,默认这个数的第一位总是1,因此可以被舍去,只保存后面的小数部分。

举例来说:

保存1.01时,只保存01,等到读取的时候,再把首位的1加上去。

这样的目的是节省1位有效数字。以32位浮点数为例,M有23位,将首位的1舍去以后,等于可以存储24位有效数字。


5. IEEE 754对E的特别规定

首先,E为一个无符号整数 (unsigned int)

E如果是8位,取值范围为0~255;E如果是11位,取值范围为0~2047。但是科学计数法中的E可以出现负数(指数出现负数),所以IEEE 754规定,存入内存时E的真实值必须再加上一个中间数

对于8位的E,这个中间数是127(例如E为-127,加上中间数127后值为0,这样才符合无符号整数的取值范围),对于11位的E,这个中间数是1023。

举例来说:

2^10的E是10,在保存成32位浮点数时,必须保存成10+127=137,即10001001。


6. 指数E从内存中取出的三种情况

6.1 E不全为0或不全为1✨

指数E的计算值减去127(或1023),得到真实值,再将有效数字M前加上第一位的1。

举例来说:

0.5的二进制形式为0.1,由于规定正数部分必须为1,所以将小数点向右移1位,则为

1.0 * 2^(-1) ,阶码()为-1+127=126,表示为01111110,尾数1.0去掉整数部分为0,二进制表示形式为:

0 01111110 000000000000000000000

(阶码:对于任意一个二进制数N,可用N=S×2^P表示,其中S为尾数,P为阶码,2为阶码的底,P、S都用二进制数表示,S表示N的全部有效数字,P指明小数点的位置。 当阶码为固定值时,数的这种表示法称为定点表示,这样的数称为“ 定点数 ”;当阶码为可变时,数的这种表示法称为 浮点 表示,这样的数称为“ 浮点数 ”。

阶码:在机器中表示一个浮点数时需要给出指数,这个指数用整数形式表示,这个整数叫做阶码。)


6.2E全为0✨

这时,指数E等于1-127(即-126) (或者1-1023(即-1022))即为真实值,有效数字M不再加上第一位的1,而是还原为0,xxxxxx的小数,这样做是为了表示±0,以及接近于0的很小的数字。


6.3E全为1✨

这时,如果有效数字M全为0,表示±无穷大(正负取决于符号位s)。


7. 解释浮点数存储的例子

int main(){int n = 9;//0 00000000 00000000000000000001001//S EM//E全为0时,浮点数的指数等于1-127(或者1-1023)即为真实值,有效数字M不再加上第一位的1,而是还原为0.xxxxxx的小数//即S=0 E=-126 M=0.00000000000000000001001//则为(-1)^0 * 0.00000000000000000001001 * 2^-126float* pFloat = (float*)&n;printf("n的值为:%d\n", n);//9printf("*pFloat的值为:%f\n", *pFloat);//0.000000*pFloat = 9.0;//1001.0//(-1)^0 * 1.001 * 2^3//得到S=0 E=3 M=1.001//存的时候E加上中间数127为130//则二进制表示形式为0 10000010 00100000000000000000000printf("num的值为:%d\n", n);//1091567616printf("*pFliat的值为:%f\n", *pFloat);//9.000000return 0;}

8. 总结

对于浮点型在内存中的存储,做到知道是怎么存的就足够了,不用死记硬背。