在数据类型中,浮点数也是很常见的,而对于浮点数的类型也多种多样:有double、float、long double类型。
一 代码示例
相对与整型在内存中的存储方式,浮点数却不相同,让我们以下列的代码为例子:
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int main() {
int num = 9;
float* p = (float*)#
printf("%d\n", num);
printf("%f\n", *p);
*p = 9.0;
printf("%d\n", num);
printf("%.1f\n", *p);
}
初看变量num,通过强制转换成float类型再通过指针解引用输出,但不能输出9的浮点数,而打印输出整型确实正确的。
当我们通过指针修改p中的数据成浮点数时,此时两者状况相反:
对于这种情况的出现,是因为浮点型与整型在内存中存储的方式不一样所导致的。
二 浮点数存储的规定
num与*p明明存放的是同一个数,为什么用整型与浮点型的解读会出现不一样的效果?下面先让我们来了解一下浮点数在计算机中的表现形式:
我们知道,数据在计算机中是用0和1进行存储的,
根据国际标准IEEE754,任意一个二进制的浮点数V可以表示成下列形式:
V = (-1) ^ S *M * 2 ^ E
(-1)^S表示符号位,当s为1时,表示V是正数,当S为0时,表示V为负数。
M表示有效数字,M的取值范围是1<=M<2。
2^E表示指数位。
这其实相当于科学计数法,以 314 * 10^3为例:
因为134 * 10^3是一个正数,所以s等于0;
因为有效数字M的范围是1<=M<2,所以我们134的整数点需要向前移动两位,所以134 * 10^3变成了1.34*10^5,E的大小为10。
用进制举例也是一样的:
以十进制的-5.0为例,转换成二进制为-101.0,用上面的办法,可以将V写成:
V=(-1)^1 * 1.01 * 2 ^ 2
S的值为1,有效值M为1.01,指数位E的大小为2。
当我们将这些数放在内存中时,V存放的顺序并不是按照S-M-E的顺序进行存放。
在IEEE754中规定:
对于32位的浮点数,最高的1位存储符号位S,接着8位存储指数E,剩下的23位存储有效数字M
对于64位的浮点数,最高的1位存储符号位S,接着11位存储指数E,剩下的52位存储有效数字M
内存图示如下:
三 浮点数的存
当浮点数进行存储时,对于M与E,IEEE754还有些规定。
对于有效数字M,因为1<=M<2,所以M可以写成1.xxxxxxxxx的形式,其中xxxxxxxxx表示小数部分,当M存于内存时,计算机会自动默认第一位数是1,因此在计算机中可以省略,只存储小数部分,当我们取出浮点数时,只需要再将第一位的1加上去即可。这样的好处是有效数字可以多存一位有效数字,以32位机器为例,原本M可以存储23位,现在可以存24位。
对于指数位E,情况就特殊许多了,首先我们需要一个清醒的认识:E是一个无符号整数。
如果E为8位,那么它的取值范围是0-255;如果E为11位,那么它的取值范围是0-2047;但是再科学计数法中,E是可以为负数的,因此IEEE规定,存入内存的E的真实值需要加上一个中间数。
对于8位的E,中间数是127;对于16位的E,中间数是1023。
一句话来说:
E+中间数 再存入内存!
比如:2^3的E是3,保存成32位浮点数时,那么存入内存的就是3+127=130,
转换成二进制就是1000 0010。
四 浮点数的取
对于指数E,在内存中取的情况也有三种:全为1,全为0,不全为1或不全为0。
情况1:E全为1
如果这时有效数字M全为0,表示+-无穷大(符号取决于S)。
情况2:E全为0
浮点数的指数E等于1-127(或1-1023)即是真实值,有效数字M不再加上第一位的1,而是还原成0.XXXXX的小数,。这样做是为了表示+-0,以及接近与0的数字。
情况3:E不全为1或不全为0
这时指数E等于1-127(或1-1023)获得真实值,再将有效数字M前加上第一位1。
五 回归代码示例
此时再让我们回到代码示例中:
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int main() {
int num = 9;
float* p = (float*)#
printf("%d\n", num);
printf("%f\n", *p);
*p = 9.0;
printf("%d\n", num);
printf("%.1f\n", *p);
}
因为num刚开始是以整型的形式进行存储,在内存中的二进制表示为:
1 0000 0000 0000 0000 0000 0000 0000 1001
如果按照浮点型的形式进行拆分,符号位S=0;后面八位代表E,E=00000000,剩下的23位有效数字M是000 0000 0000 0000 0000 1001 ,符合E全为0的情况,所以V是一个接近于0的数字,所以用十进制小数表示就是0.000000。
再看浮点数9.0,整数的打印为什么是1091567616?
那么先让我们将9.0在内存中的存放:
9.0的二进制数是1001.0,换算成科学计数法是1.001*10^3,
V=(-1)^0 *1.001 *2^3
对于32位浮点数,符号位为0,
指数位E存放进内存中实际上是3+127=130,转换成二进制是10000010,有效数字自动省略第一位的1,后面再加20位0凑够23位,那么有效位置的二进制是 001 0000 0000 0000 0000 0000
那么最后以浮点型存放进内存的二进制码为:
0 10000010 001 0000 0000 0000 0000 0000
在计算器中转换成十进制时,得出的结果刚好是 1091567616,也就是我们通过整型读取浮点型的结果。
感谢观看,希望这篇文章能帮助到您了解浮点型的存储。
如果文章有错误或不足之处还请联系更正。