第3课 - 浮点数的秘密
1. 浮点数在内存中的存储方式
float与double类型的数据在计算机内部的表示法是相同的,但由于所占存储空间的不同,其分别能够表示的数值范围和精度不同。
2. 浮点数的转换
2.1 浮点数的转换方法
如何将十进制的浮点数转换为内存中二进制表示的浮点数呢?按照下面三个步骤:
① 将浮点数转换为二进制
② 用科学计数法表示二进制浮点数
③ 计算指数偏移后的值(需要加上偏移量,float型:指数 + 127,double型:指数 + 1023)
比如对于指数6,float型偏移量就为 127 + 6 = 133,double型偏移量为1023 + 6 = 1029
2.2 浮点数的转换示例
下面以十进制的 8.25 演示一下上述的转换方法。
① 将8.25转换为二进制(注意小数的二进制表示方法) ==> 1000.01
② 用科学计数法表示1000.01(注意这里是二进制,2^3) ==> 1.00001(2^3)
③ 指数3偏移后为:127 + 3 = 130
所以浮点数8.25对应的符号位、指数、尾数分别为:
符号位:0
指数:130 ==> 10000010
小数:00001 // 要将小数转为尾数,需要在后面补0
8.25在内存中的二进制表示为:0 1000 0010 000 01000000 0000 0000 0000 = 0x41040000
下面我们写代码验证一下:
1 #include <stdio.h> 2 3 int main() 4 { 5 float f = 8.25; 6 unsigned int *p = (int *)&f; 7 8 printf("f = 0x%08x ", *p); 9 10 return 0; 11 }
结果和我们前面分析的相同。
3. 浮点数的秘密
我们知道int型数据占用4个字节,表示的范围为:【-231 , 231-1】;float型也占用4个字节,表示的范围为:【-3.4*1038,3.4*1038】。
看到这里不少人很奇怪,4个字节按照排列组合能表示的数据范围应该是固定的,为什么float类型表示的范围却比int型的大?这里我们就要揭露一下float类型的秘密了。
(1)float能表示的具体数值的个数与int型相同,因为都是4字节,排列组合都是232-1个
(2)之所以float表示出来的范围比int型大,是因为float可表示的数字之间是不连续的,数据之间存在跳跃
(3)float只是一种近似的表示法,不能作为精确数使用
(4)由于float类型的内存表示方法相对复杂,float的运算速度比int慢很多
※ 因为double与float具有相同的内存表示法,所以double也是不精确的。由于double占用的内存较多,所能表示的精度比float高。
【float类型的不精确示例】
1 #include<stdio.h> 2 3 int main() 4 { 5 float f1 = 3.1415f; 6 float f2 = 123456789; 7 8 // 精确到小数点后面的10位 9 printf("%0.10f ", f1); // 3.1414999962 ==> 不等于3.1415,表示的结果是不精确的 10 printf("%0.10f ", f2); // 123456792.0000000000 ==> 与123456789不相等,表示的数据是不连续的、跳跃的 11 12 return 0; 13 }
再添加0.25和1.25的转换方法,加深理解:
0.25
① 0.25 转换为二进制 0.01
② 二进制0.01用科学计数法表示 1.0*(2^-2),指数为 -2 + 127 = 125
③ 小数为0
所以0.25在内存中表示为:0 01111101 00000000000000000000000 = 0x3e800000
1.25
① 1.25转换为二进制 1.01
② 二进制1.01用科学计数法表示1.01*(2^0) ,指数为 0 + 127 = 127
③ 小数为0.25
所以1.25在内存中表示为:0 01111111 01000000000000000000000 = 0x3fa00000