实型数据又称为浮点型数据。实型数据可分为单精度实型(float型)和双精度实型(double型)。
数据类型 | 类型说明关键字 | 占用字节 | 取值范围 | 精度(位) |
单精度浮点型 | float | 4 | ±(3.4*10^-38 ~ 3.4*10^38) | 7 |
双精度浮点型 | double | 8 | ±(1.7*10^-308 ~ 1.7*10^308) | 15 |
float类型的存储格式:
符号位(1位) | 阶码(8位) | 尾数(23位) |
31 30 22 0
double类型的存储格式:
符号位(1位) | 阶码(11位) | 尾数(52位) |
63 62 51 0
符号位:最高位表示符号位,0表示整数,1表示负数;
阶码:也即是2的指数,如2^12,其中,12就是指数,也即阶码。阶码占8位,为了表示负数,引入了偏移量的概念,float型的偏移量为127(double型的偏移量为1023)。如果阶码为200,则表示的实际阶码为(200-127)也即73。
尾数:以2进制科学计数法表示后的小数部分。(整数部分默认为1,不存储,所以就可以用23位表示24位的精度,或以52位表示53位的精度)
举例将17.625换算成 float型。
首先,将17.625换算成二进制位:10001.101 ( 0.625 = 0.5+0.125 =2^-1 + 2^-3)
再将 10001.101 表示为科学计数法的格式,也即1.0001101*10^4
符号位:由于是整数,所以为0
阶码:实际阶码为4,加上偏移量127,即为131,对应的二进制为10000011
尾数:由于整数部分默认为1,所以尾数部分只取0001101,不够23位,在末尾补0。如果尾数超过23位,则舍去超过的部分,但是如果第24位为1,则产生进位;如果第24位为0,直接舍去超过部分。
综上所述,17.625的 float 存储格式就是:
0 10000011 00011010000000000000000
下面举例说明上面红色字的含义,先从一个具体的例子说起:
unsigned int u = 4294967295;
float f = u;
printf(“%f\n”, f);
最后输出结果会是多少呢?
输出结果为:4294967296.000000
为什么会出现上面的结果呢?float表示的范围比unsigned int 表示的范围大,输出的结果应该是4294967295.000000才对啊,但是为什么是4294967296.000000呢?这主要是由于float类型与unsigned int类型的存储格式不同造成的。
我们看看,4294967295的二进制为1111 1111 1111 1111 1111 1111 1111 1111
按照上面的例子可以将该二进制转换为float类型的存储格式为:(直接舍去超过23位的部分)
0 10011110 1111 1111 1111 1111 1111 111
但是尾数的第24位为1,所以会产生进位,由于尾数为全1,所以会将指数部分加1。
所以4294967295的float类型存储格式为:
0 10011111 0000 0000 0000 0000 0000 000
再回到上面的程序段,当以float型输出变量f的值时,就会根据float类型的存储格式去还原为float型的值。也即:1. 0000 0000 0000 0000 0000 000 *2^(159-127)= 2^32 = 4294967296.000000(float保留6位小数)ps: 159的二进制为1001 1111