常见的浮点数类型:float、double、long double。 ::: tip 浮点数的表示范围是在float.h中定义。整型类型的表示范围在limits.h中定义。 :::
浮点数在计算机内部的表示方法
::: tip 浮点型的二进制数需要小数点前和小数点后分别计算二进制序列。 步骤是浮点数计算成二进制序列,改写成科学计数法形式,加上符号位。 ::: 32位浮点数最高一位是符号位s,接着8位是指数E,剩下的23位是有效数字M。 64位浮点数最高一位是符号位s,接着11位是指数E,剩下的52位是有效数字M。
M和E的特殊规定
IEEE 754对于有效数字M的特殊规定: 对于任意一个数字,写成二进制数的形式时,都是1≤M≤2,将M写成1.xxxxxx,只保存小数部分的xxxxxx。即存储时将小数点前的1省略,取出时补上。当内存中的有效数字位都用来存储小数点后的数字时,精度高一位。
IEEE 754对于指数E的特殊规定: 在存储时E的8个或11个比特位中没有符号位,即E是无符号数(unsigned int)。单精度浮点数的E取值范围是0
255,双精度浮点数的E取值范围是 02047。但科学计数法的E可以出现负数。 IEEE 754规定在存入内存时E的真实值(无论正负)需要加上中间数(用来转换成正数(无符号数)),对于8位的E,中间数是127;对于11位的E,中间数是1023。
例如:0.5的二进制表示是0.1,科学计数法表示是(-1)^01.02^-1,E为-1,存储进内存时,E+127变为126,此时E的真实值需要E-127得到。
int main()
{
float a = 5.5;
//5.5 - 十进制
//101.1 - 二进制
//(-1)^0*1.011*2^2 - 科学计数法
//S = 0
//M = 1.011
//E = 2
//E = 2 + 127 = 129 - 加上中间数存进内存
//10000001 - E的二进制序列
//0 10000001 01100000000000000000000 - 内存中由S、E、M组成
//0100 0000 1011 0000 0000 0000 0000 0000
//0x40b00000 - 改为16进制写法
return 0;
}
E取出的三种情况
- E不全为0或不全为1 常规情况。E减去127或1023还原为真实值。M前补上1和小数点。再组合成(-1)^0* M* 2^E。
- E全为0 E加上127后的值为0,则E的真实值为-127。即±1.xxx* 2^-127,是一个非常接近于0的值。特殊规定如下:
- 当浮点数的指数E等于1-127或1-1023时即为真实值。有效数字M前不再补1和小数点。此时数字为0.xxxxxx的小数,便于表示±0和接近于0的很小数字。* 组合后是±0.xxxxxx*2^-126。
- E全为1 E加上127后的值为255,则E的真实值为128。即±1.xxxxxx*2^128,表示正负无穷大的值。
浮点数存储举例
int main()
{
int n = 9;
//00000000000000000000000000001001 - 补码
float* pFloat = (float*)&n;
printf("n的值是%d\n",n);
//00000000000000000000000000001001 - 整型视角
printf("*pFloat的值为%f\n",*pFloat);
//0 00000000 00000000000000000001001 - 浮点型视角
//E为全0时,M前补0和小数点,E取1-127,如下:
//(-1)^0*0.00000000000000000001001*2^126
//(%f输出float类型,输出6为小数)
*pFloat = 9.0;
//1001.0 - n的二进制序列
//0*1.001*2^3 - 科学计数法
//(-1)^0*1.001*2^3 - 存入内存中如下:
//0 10000010 00100000000000000000000 - E = 3 + 127
printf("num的值是%d\n", n);
//01000001000100000000000000000000 - 整型视角
//1091567616 - 符号位为,正数原反补相同,%d打印十进制数
printf("*pFloat的值为%f\n", *pFloat);
return 0;
}
n的值是9
*pFloat的值为0.000000
num的值是1091567616
*pFloat的值为9.000000
第6行代码以整形的形式存储,浮点型的形式取出,结果不是预想得到的。 第10行代码以浮点数的形式存储,整型的形式取出,结果不是预想得到的。 上述代码的结果可以看出内存中整型和浮点型存储的方式是不同的。 *pFloat解引用后一次可以访问4个字节。
::: tip 上述代码中n的类型是int,地址是int,赋给float类型的指针时进行强制类型转换。 *变量的地址的类型和变量的类型相同,如果需要赋给其他类型的指针,需要强制类型转换。**(如果没有精度丢失的情况,不会发生值的变化)。 :::