float数据类型及double数据类型整理
float数据类型在内存中的存储形式介绍:
float在内存中的存储遵循IEEE 754标准。在C/C++中,float类型占4个字节即32位,这32位分成了3部分:符号位:转化成⼆进制后,第31位。 0代表正数,1代表负数
阶码:30-23位,转化成规格化的⼆进制之后与127之和
尾数:22-0位
例如:13.625在内存中的存储
⾸先将13.625转化成⼆进制
整数部分除2取余,直到商为0停⽌。最后读数时,从最后⼀个余数读起,⼀直到最前⾯的⼀个余数
所以整数部分13的⼆进制位  1101;
⼩数部分乘2取整,然后从前往后读。
0.625*2 = 1.25        取整      1
0.25*2  = 0.5          取整      0
0.5*2    = 1            取整      1
所以⼩数部分的⼆进制  101
然后将 1101.101的⼩数点向左移⾄⼩数点前只有⼀个1,即左移3位。(这⾥为⼆进制的特定表⽰⽅法,将整数部分划为1)阶码就是3+127 = 130  即:1000 0010
符号位:0
尾数:因为⼩数点前必为⼀,所以记录⼩数点后⾯的数即可 101101
0100 0001 0101 1010 0000 0000 0000 0000
转换成16进制后为 41 5A 00 00
float/double类型数据在内存中中存储格式
float/double类型数据在计算机是如何存储的呢?
它们是ieee standard 754的存储⽅式。譬如float数,第⼀位是符号位,然后是8位指数位,然后是23位尾数;double双精度格式为8字节64位,由三个字段组成:52位⼩数f,11位偏置指数e,以及1位符号s,这些字段连续存储在两个32位字中。
存储结构
浮点型变量float
类型符号位指数位尾数位
float00xff0x7fffff
double00x7ff0xfffffffffffff
注意
上⾯的存储结构,由于字节太多,所以后⾯使⽤的⼗六进制表⽰,7代表3位,f代表4位
浮点类型
从存储结构和算法上来讲,double和float是⼀样的,不⼀样的地⽅仅仅是float是32位的,double是64位的,所以double能存储更⾼的精度以及更⼤的数值。float表⽰的正数范围是
3.40282346638528859811704183484516925440e+38~1.401298464324817070923729583289916131280e-45,double的正数范围是1.797693134862315708145274237317043567981e+308~
4.940656458412465441765687928682213723651e-324
【注:个⼈认为,从阶码上移位来算,整数部分的确可以表⽰这么⼤的数据范围,但是从却受到后⾯
尾数的限制,float的有效位数只有6-7位,double的有效位数为15-16位(⾄于具体为什么是6-7位、15-16位看下⾯的总结部分),所以感觉上⾯表⽰这么⼤的数据范围实际上意义不⼤。】
可以看出来double的表⽰的范围⽐float⼤,⽽且由于尾数增加,实际上,精确度也⽐float⾼,但这样的优势带来的就是更低的计算效率,虽然个⼈觉得不论是float还是double计算效率都被整形完爆,所以能够⽤整型操作,就尽量不要⽤浮点型。
另外⼀个主要注意的则是,我们可以看到这⾥该数的表⽰范围并不像整形那样,直接可以表⽰0,⽽是是⼀个很⼤到⼀个很接近0的数值,所以很多情况下浮点数判断是否为0,不是直接跟0⽐较是不是相等,⽽是约定⼀个很⼩的数,如果⼩于这个数,就等于0.
实际在内存中的存储顺序
任何数据在内存中都是以⼆进制(0或1)顺序存储的,每⼀个1或0被称为1位,⽽在x86CPU上⼀个字节是8位。⽐如⼀个16位(2字节)的short int型变量的值是1000,那么它的⼆进制表达就是:00000011 11101000。由于Intel CPU的架构是⼩尾端表⽰,它是按字节倒序存储的,那么就因该是这样:11101000 00000011,这就是定点数1000在内存中的结构。(如果这⾥不明⽩为什么这样,可以搜索⼤尾端⼩尾端概念)
⽬前C/C++编译器标准都遵照IEEE制定的浮点数表⽰法来进⾏float,double运算。这种结构是⼀种科学计数法,⽤符号、指数和尾数来表⽰,底数定为2——即把⼀个浮点数表⽰为尾数乘以2的指数次⽅再添上符号。下⾯是具体的规格:
类型符号位阶码尾数长度
float182332
double1115264
实战:⼗进制转⼗六进制
下⾯以double38414.4为例:
1. 把整数部和⼩数部分开处理:整数部直接化⼗六进制:960E。
2. ⼩数的处理: 0.4=0.5*0+0.25*1+0.125*1+0.0625*0+……
你会发现第⼆步根本是坑爹嘛,根本算不完,那么该怎么办呢?加上前⾯整数的精度960E,你只需要算够53位就⾏了(最⾼位的1不写⼊内存)。⼿⼯算到53位是:38414.4(10)=1001011000001110.011001100110011001100110011001100110011(2)
科学记数法:1.001……乘以2的15次⽅。
(注意指数是15,这⾥的指数是2的次⽅,不是10的次⽅)
然后看阶码,⼀共11位,可以表⽰范围是-1024 ~ 1023。因为指数可以为负,为了便于计算,规定都先加上1023,在这⾥,
15+1023=1038。⼆进制表⽰为:100 00001110
符号位:正—— 0 !
合在⼀起(尾数⼆进制最⾼位的1不要):
01000000 11100010 11000001 11001101 01010101 01010101 01010101 01010101
假定机器为⼩尾端,字节倒序存储的⼗六进制数就是:
55 55 55 55 CD C1 E2 40
协议参考⽹址
IEEE Standard 754 for Binary Floating-Point Arithmetic
--------------------------------------------------------------------------------------
总结:
1 范围
float和double的范围是由指数的位数来决定的。
float的指数位有8位,⽽double的指数位有11位,分布如下:
float:
1bit(符号位)8bits(指数位)23bits(尾数位)
double:
1bit(符号位)11bits(指数位)52bits(尾数位)
于是,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位有效数字;
【也可以这么算,0.000001的精度为10^(-6), 2^20 = 1048576; 1/1048576的精度⾼于10^(-6), 但是23位不够表⽰10^(-7),所以为有效位数为6-7位;】double:2^52 = 4503599627370496,⼀共16位,同理,double的精度为15~16位。
所以,float数据类型受到有限的有效位数限制,不能表⽰精度⾼的浮点型数据;