c中不管32位还是64位机,float所占字节均为4字节,即32位,根据IEEE R32.24标准,float在内存中的存储格式为1位符号位,8位指数位,23位尾数位。
其中指数位算数取值范围为[0 ~ 255],但根据IEEE754标准,全0和全1分表代表浮点数0和浮点数无穷,被舍去,即0和255被舍去,所以范围变成[1 ~ 254],由于这是一整个数的一部分,不区分符号位,所以为了表示正负数,设立了偏移量,根据有符号8位取值范围[-127 ~ -0,0 ~ 127]去掉全0和全1变成[-126 ~ 127]得到偏移量为127,这样1即为-126,126即为-1。
由于浮点数在内存中是按科学计算法存储的,即 6.125 => 0b110.001 => 0b1.10001 * 22 ,由于任何浮点数都可以按1.x···x * 2n 表示,所以这里的个位数1就可以隐藏,所以23位尾数位就可以全部表示科学计数里的小数位,那么float可表示的最大绝对值数为 0b1.11111111111111111111111 * 2127,即为 (0b10 - 0b0.00000000000000000000001) * 2127 ,即 (2 - 2-23) * 2127 ,而 2 - 2-23 约等于2,即为 2128 ,所以初步计算,float范围为[-2128 ~ 2128]。
又由于指数位最小为-126,尾数位最小为全0,则float可表示的最小绝对值数为 0b1 * 2-126 ,即为 2-126 ,所以float取值范围为 [-2128 ~ -2-126,2-126 ~ 2128] 。
对于float精度,由于隐藏位始终为1,不作考虑,那么23位二进制数最多能表示8388607个数字,想再多表示一些数字,就会越位,一旦数字超出23位,存储时就意味着丢失精确值,使用的是近似值,这也就是为什么float数值到一定程度时是跳跃的,例如十进制1.2 转二进制为 0b1.00110011001100110011001(0011无限循环),这时候再转成十进制就变成了1.19999992847442627这个值,从这个例子也可以看出,位数越多,才能越无限趋近于1.2,23位所表示的趋近于1.2的精度也就7位,所以结合8388607这个数字以及更多的例子就可以得出float所能表示的十进制数最大精度为7位的结论。(关于精度,参考https://blog.csdn.net/albertsh/article/details/92385277这篇博客内容,因为当指数位为全0,且尾数位不为全0时,尾数中隐藏位可认为是0,则尾数位实际可表示最大数为224 - 1,即16777215,由于最高位是1,不能表示8位所有数,所以精度为7。)
关于指数位全0和全1,分别称为“非规格化值”和“特殊值”,其他为“规格化值”。
非规格化值:一方面用于表示0,另一方面表示接近于0的数。因为规格化值默认隐藏个位数1,所以表示是 [1~2) 范围内的数,所以指数位全0且尾数位不为全0时,无隐藏个位数1,或认为个位数是0,因此可提高所能最大表示的数,由原来223 - 1提高到224 - 1。而当指数位和尾数位全0时,根据符号位不同,区分-0.0和+0.0。
特殊值:当尾数位全0,根据符号位不同分别表示正无穷和负无穷;当尾数位不是全0,表示NaN。