偶然间看到float的取值范围是-3.4*10^38到3.4*10^38,然后有效位数是6位或者7位(和编译器有关),突发奇想,想知道float和double的取值范围是如何计算出来的,了解了一下,大概做个总结。
首先说一下Float
1.Float的内存结构
首先我们需要了解一下float的内存结构,弄清楚它在内存中是如何存放的。
float和整形(int等)存放的方式不一样,是以指数方式(科学计数法)的方式存储的。分为三个部分。符号位,指数部分,尾数部分,float占4个字节,总共32位,其中符号位占一位,指数占8位,尾数占23位,数字9.25的存储结构如下图所示:
符号位就是表示当前变量的正负,1正0负
这个例子的表示的float的值是:1.00101 * 2^3,也就是 1001.01,转换成10进制就是9+=9.25,具体是为什么呢,可以往下看
指数部分
float的指数位没有符号,在内存中将指数+127存储。
图中指数部分是1000 0010,对应的十进制数是130,实际上的指数值需要减去127,也就是3,所以例子中对应的指数就是3,
以这种存储方式,指数的范围是[-127,128],但是float是需要表达NaN(不是一个数字)与Inf(无穷大)的,此时指数位需要来标示,所以全1情况被用掉,另外0特殊表达,指数全0情况也被用掉(当float定义的变量值为0的时候,使用指数全0和尾数全0来表示)。 所以去掉一个最大值,一个最小值,指数表达的范围是:[-126,127]
尾数部分
尾数部分占23位,但是实际上是24位1第一位1被省略,例子中9.25对应的二进制数是1001.01,,1001.01可以写成。我们可以发现,只要我们要存储的数值不为0,任何数都可以写成1.xxxxx ,所以我们第一位数是可以省略的,不用存储,尾数部分存储的就是小数点后面的内容,小数点也不用存储。我们存在内存中的数就是0010 1000 0000 0000.........(总共23位尾数)
如果要float变量的值为0,那就让尾数和指数全为0,以此来表示0,这是一种特殊情况。
2.float的取值范围分析
所以float的最大值最小值怎么出来呢?
指数全1的情况(255-127)为了表示特殊的值被用掉了,所以指数最大是254-127=127,尾数省略1和小数点,所以为了使尾数最大,取全1,这时候尾数 = ,这个数非常接近2,所以最后的值就是2*2^127 = 2*1.7014 E38,大概就是3.4E38左右,
最小就是将符号位变成1,表示负数,其他没有任何区别。
double的话指数长度为11位,尾数长度为52位,存储原理是一样的。
大家有什么想法可以和我评论交流~