概述
float和double的区别
- double是双精度浮点数,内存占8个字节,有效数字16位,表示范围是-1.79E+ 308~-1.79E+308。
float是单精度浮点数,内存占4个字节,有效数字8位,表示范围是 -3.40E+38~3.40E+38。 - 两者处理速度不同,CPU处理float的速度比处理double快。double的精度高,double消耗内存是float的两倍。
- 如果不声明,小数默认是double类型,用float时需要进行强转,或者在小数后加上f。
float与double的范围和精度
1 范围
float和double的范围是由指数的位数来决定的。
float的指数位有8位,而double的指数位有11位,分布如下:
float:
1bit(符号位) | 8bits(指数位) | 23bits(尾数位) |
---|
double:
1bit(符号位) | 11bits(指数位) | 52bits(尾数位) |
---|
在数学中,特别是在计算机相关的数字(浮点数)问题的表述中,有一个基本表达法:
value of floating-point = significand xbase ^ exponent , with sign
译为中文表达即为:
(浮点)数值 = 尾数 × 底数 ^ 指数,(附加正负号)
于是,float的指数范围为-127 ~ 128,而double的指数范围为-1023 ~ 1024,并且指数位是按补码的形式来划分的。其中负指数决定了浮点数所能表达的绝对值最小的数;而正指数决定了浮点数所能表达的绝对值最大的数,也即决定了浮点数的取值范围。
float的范围为-2^128 ~ +2^128,也即-3.40E+38 ~ +3.40E+38;double的范围为-2^1024 ~ +2^1024,也即-1.79E+308 ~ +1.79E+308。
2 精度
float和double的精度是由尾数的位数来决定的。浮点数在内存中是按科学计数法来存储的,其整数部分始终是一个隐含着的“1”,由于它是不变的,故不能对精度造成影响。
float:2^23 = 8388608,一共七位,这意味着最多能有7位有效数字,但绝对能保证的为6位,也即float的精度为6~7位有效数字;
double:2^52 = 4503599627370496,一共16位,同理,double的精度为15~16位。
单精度类型(float)和双精度类型(double)存储
在C 语言中,对于浮点类型的数据采用单精度类型(float)和双精度类型(double)来存储,float数据占用 32bit, double数据占用64bit,我们在声明一个变量float f= 2.25f的时候,是如何分配内存的呢?如果胡乱分配,那世界岂不是乱套了么,其实不论是float还是double在存储方式上都是遵从IEEE的规范 的,float遵从的是IEEE R32.24 ,而double 遵从的是R64.53。
R32.24和R64.53的存储方式都是用科学计数法来存储数据的,科学计数法是将所有的数字转换成(±)a.b * 10^c的形式,其中a的范围是1到9共9个整数,b是小数点后的所有数字,c是10的指数。而计算机中存储的都是二进制数据,所以存储的数字都要先转化成(±)a.b * 2^c ,由于二进制中最大的数字就是1,所以表示法可以写成(±)1.b *2^c 的形式,要想存储小数就只需要存储(±),b和c就可以了。
float的存储正是将4字节32位划分为了3部分来分别存储正负号,小数部分和指数部分的:
- Sign(1位):用来表示浮点数是正数还是负数,0表示正数,1表示负数。
- Exponent(8位):指数部分。即上文提到数字c,但是这里不是直接存储c,为了同时表示正负指数以及他们的大小顺序,这里实际存储的是c+127。
- Mantissa(23位):尾数部分。也就是上文中提到的数字b
三部分在内存中的分布如下,用首字母代替类型
S | E | E | E | E | E | E | E | E | M | M | M | M | M | M | M | M | M | M | M | M | M | M | M | M | M | M | M | M | M | M | M |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 0 | 0 | 0 | 1 | 1 | 0 | 0 | 1 | 1 | 0 | 0 | 1 | 1 | 0 | 0 | 1 | 1 | 0 | 0 | 1 | 1 | 1 |
double的存储正是将8字节64位划分为了3部分来分别存储正负号,小数部分和指数部分的:
- Sign(1位):用来表示浮点数是正数还是负数,0表示正数,1表示负数。
- Exponent(11位):指数部分。即上文提到数字c,但是这里不是直接存储c,为了同时表示正负指数以及他们的大小顺序,这里实际存储的是c+127。
- Mantissa(52位):尾数部分。也就是上文中提到的数字b
三部分在内存中的分布如下,用首字母代替类型
S | E | E | E | E | E | E | E | E | E | E | E | M | M | M | M | M | M | M | M | M | M | M | M | M | M | M | M | M | M | M | M |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 0 | 0 | 0 | 1 | 1 | 0 | 0 | 1 | 1 | 0 | 0 | 1 | 1 | 0 | 0 | 1 | 1 | 0 | 0 | 1 | 1 | 0 |
M | M | M | M | M | M | M | M | M | M | M | M | M | M | M | M | M | M | M | M | M | M | M | M | M | M | M | M | M | M | M | M |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | 1 | 1 | 1 | 1 | 0 | 0 | 0 | 1 | 1 | 0 | 0 | 1 | 1 | 0 | 0 | 1 | 1 | 0 | 0 | 1 | 1 | 0 | 0 | 1 | 1 | 0 | 1 | 1 | 0 | 1 | 1 |
float存储示例
以数字6.5为例,看一下这个数字是怎么存储在float变量中的:
先来看整数部分,模2求余可以得到二进制表示为110。
再来看小数部分,乘2取整可以得到二进制表示为.1(十进制的小数转换为二进制,主要是小数部分乘以2,取整数部分依次从左往右放在小数点后,直至小数点后为0)。
拼接在一起得到110.1然后写成类似于科学计数法的样子,得到1.101 * 2^2。
从上面的公式中可以知道符号为正,尾数是101,指数是2。
符号为正,那么第一位填0,指数是2,加上偏移量127等于129,二进制表示为10000001,填到2-9位,剩下的尾数101填到尾数位上即可
S | E | E | E | E | E | E | E | E | M | M | M | M | M | M | M | M | M | M | M | M | M | M | M | M | M | M | M | M | M | M | M |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
内存中二进制数01000000 11010000 00000000 00000000表示的就是浮点数6.5
而双精度浮点数的存储和单精度的存储大同小异,不同的是指数部分和尾数部分的位数。所以这里不再详细的介绍双精度的存储方式了。
最后
以上就是勤劳香烟为你收集整理的float与double的范围和精度的全部内容,希望文章能够帮你解决float与double的范围和精度所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复