【C进阶】3、浮点数的秘密

Summary 1)浮点数在内存中的存储方式:

类型 符号位 指数 尾数
float 1位(第31位) 8位(第23-30位) 23位(第0-22位)
double 1位(第63位) 11位(第52-62位) 52位(第0-51位)
2)float与double类型的数据在计算机内部的表示法是相同的,但是由于所占存储空间大小的不同,其分别能够表示的数值范围和精度不同
【【C进阶】3、浮点数的秘密】3)浮点数的转换
如:浮点数-8.25的二进制转换,float类型:
1. 符号位:1(负数)
2. 绝对值二进制:1000.01(整数部分的指数依次为0,1,2...; 负数部分的指数一次为-1,-2,-3...)
3. 科学计数法:1.00001 * 23,指数为3
4. 指数+偏移:3 + 127 = 130 <--> 1000 0010(float的指数占8位
5. 尾数:尾数部分为00001,占23位,不足的后面补0:00001 0000 0000 0000 0000 00
6. 最终:二进制为:1 1000 0010 00001000000000000000000(符号位 + 指数 + 尾数);用16进制表示为:0xc1040000
注意
  • 对于float类型,指数的偏移为+127;对于double类型,指数的偏移为+1023。尾数部分,不足的位数后面补0
  • 通过如下指针方式,可以获得一段内存中的二进制位
    unsigned int* p = (unsigned int*)&val; printf("%08x", *p); // %08x表示以16进制的形式来打印内存里的值

4)float能表示的具体数字的个数与int相同(都占用4个字节,一共32个bit位,所以最多就232种排列组合方式,即最多能表示232个数)
5)float的表示法是不精确的,所以能表示的范围比int大。由于float的值不精确,所以对于一个float值,直接打印的数据可能有偏差;同时对于浮点数的运算,不能直接和0比较
6)因为float的内存表示法比int复杂,所以float的运算速度比int
浮点数的秘密 1、浮点数在内存中的存储方式
类型 符号位 指数 尾数
float 1位(第31位) 8位(第23-30位) 23位(第0-22位)
double 1位(第63位) 11位(第52-62位) 52位(第0-51位)
float与double类型的数据在计算机内部的表示法是相同的,但是由于所占存储空间大小的不同,其分别能够表示的数值范围和精度不同
2、浮点数的转换 如:浮点数-8.25的二进制转换,float类型:
1. 符号位:1(负数)
2. 绝对值二进制:1000.01(整数部分的指数依次为0,1,2...; 负数部分的指数一次为-1,-2,-3...)
3. 科学计数法:1.00001 * 23,指数为3
4. 指数+偏移:3 + 127 = 130 <--> 1000 0010(float的指数占8位
5. 尾数:尾数部分为00001,占23位,不足的后面补0:00001 0000 0000 0000 0000 00
6. 最终:二进制为:1 1000 0010 00001000000000000000000(符号位 + 指数 + 尾数);用16进制表示为:0xc1040000
float f = -8.25f; // f指明为float类型 unsigned int* p = (unsigned int*)&f; // 用指针指向该浮点数的内存,并'以无符号整型数来表示' printf("0x%08X\n", *p); // %08X,表示以16进制大写的形式来打印值,通常'用来打印内存的二进制位'// 输出为:0xC104 0000,和笔算结果一致。

如果已知一个32位二进制表示一个浮点数,则推算结果和上面相反
3、浮点数深入理解 int类型的范围:[-231, 231-1]
float类型的范围:[-3.4 x 1038, 3.4 x 1038]
问题:为什么int和float都占用4个字节的内存,而float却比int的范围大的多呢?
解析:
  • float能表示的具体数字的个数与int相同(都占用4个字节,一共32个bit位,所以最多就232种排列组合方式,即最多能表示232个数)
  • float可表示的数字之间是不连续的,有间隙的
  • float只是一种近似的表示法,不能作为精确数来使用
  • 由于内存表示法相对复杂,float的运算速度比int慢的多
另:double和float的内存表示法是相同的,所以也是不精确的。由于double占用的字节数比float多,所以double表示的精度比float高。
float f1 = 3.1415f; float f2 = 123456789; // 打印小数点后10位 printf("%0.10f\n", f1); // 3.1414999962 printf("%0.10f\n", f2); // 123456792.0000000000

本文总结自“狄泰软件学院”唐佐林老师《C语言进阶课程》。
如有错漏之处,恳请指正。

    推荐阅读