float内存存储方式

任何数据在内存中都是以二进制(1或着0)顺序存储的,每一个1或着0被称为1位,而在x86CPU上一个字节是8位。比如一个16位(2字节)的 short int型变量的值是1156,那么它的二进制表达就是:00000100 10000100。由于Intel CPU的架构是Little Endian(请参数机算机原理相关知识),所以它是按字节倒序存储的,那么就因该是这样:10000100 00000100,这就是定点数1156在内存中的结构。

那么浮点数是如何存储的呢?目前已知的所有的C/C++编译器都是按照 IEEE(国际电子电器工程师协会)制定的IEEE 浮点数表示法来进行运算的。这种结构是一种科学表示法,用符号(正或负)、指数和尾数来表示,底数被确定为2,也就是说是把一个浮点数表示为尾数乘以2的指数次方再加上符号。下面来看一下具体的float的规格:

float
共计32位,折合4字节
由最高到最低位分别是第 31、30、29、……、0位
31位是符号位,1表示该数为负,0反之。
30-23位,一共8位是指数位。
22-0位,一共23 位是尾数位。
每8位分为一组,分成4组,分别是A组、B组、C组、D组。
每一组是一个字节,在内存中逆序存储,即:DCBA

我们先不考虑逆序存储的问题,因为那样会把读者彻底搞晕,所以我先按照顺序的来讲,最后再把他们翻过来就行了。

现在让我们按照IEEE浮点数表示法,一步步的将float型浮点数12345.0f转换为十六进制代码。在处理这种不带小数的浮点数时,直接将整数部转化为二进制表示:1 11100010 01000000也可以这样表示:11110001001000000.0然后将小数点向左移,一直移到离最高位只有1位,就是最高位的 1:1.11100010 01000000一共移动了16位,在布耳运算中小数点每向左移一位就等于在以2为底的科学计算法表示中指数+1,所以原数就等于这样:1.11100010010000000 * ( 2 ^ 16 )好了,现在我们要的尾数和指数都出来了。显而易见,最高位永远是1,因为你不可能把买了16个鸡蛋说成是买了0016个鸡蛋吧?所以这个1我们还有必要保留他吗?没有!好的,我们删掉他。这样尾数的二进制就变成了:11100010 010000000 最后在尾数的后面补0,一直到补够23位:11100010 01000000 0000000

再回来看指数,一共8位,可以表示范围是0 - 255的无符号整数,也可以表示-128 - 127的有符号整数。但因为指数是可以为负的,所以为了统一把十进制的整数化为二进制时,都先加上127,在这里,我们的16加上127后就变成了 143,二进制表示为:10001111
12345.0f这个数是正的,所以符号位是0,那么我们按照前面讲的格式把它拼起来:
0 10001111(指数)       1110001 00100000 00000000(尾数)
0  1000111  11110001   00100000   00000000
再转化为16进制为:47 F1 20 00,最后把它翻过来,就成了:00 20 F1 47。
现在你自己把54321.0f转为二进制表示,自己动手练一下!

有了上面的基础后,下面我再举一个带小数的例子来看一下为什么会出现精度问题。
按照IEEE浮点数表示法,将 float型浮点数123.456f()转换为十六进制代码。对于这种带小数的就需要把整数部和小数部分开处理。整数部直接化二进制:100100011。小数部的处理比较麻烦一些,也不太好讲,可能反着讲效果好一点,比如有一个十进制纯小数0.57826,那么5是十分位,位阶是1/10;7是百分位,位阶是1/100;8是千分位,位阶是1/1000……,这些位阶分母的关系是10^1、10^2、10^3……,现假设每一位的序列是{S1、S2、 S3、……、Sn},在这里就是5、7、8、2、6,而这个纯小数就可以这样表示:n = S1 * ( 1 / ( 10 ^ 1 ) ) + S2 * ( 1 / ( 10 ^ 2 ) ) + S3 * ( 1 / ( 10 ^ 3 ) ) + …… + Sn * ( 1 / ( 10 ^ n ) )。把这个公式推广到b进制纯小数中就是这样:
n = S1 * ( 1 / ( b ^ 1 ) ) + S2 * ( 1 / ( b ^ 2 ) ) + S3 * ( 1 / ( b ^ 3 ) ) + …… + Sn * ( 1 / ( b ^ n ) )

 

 

float 内存如何存储的

 

 

类型
存储位数
总位数
偏移值
(offset)
数符 (S)
阶码 (E)
尾数 (M)
短实数 (float)  
   1 
   8
  23
   32
127
长实数 (double)
   1
   11
  52
   64
 1023
 

 

N (10) = 123.456,

换算成二进制表示:

N (2) = 1111011. 01110100101111001

= 1. 11101101110100101111001(...) * 2^6

   那么E – 127 = 6;  E = 127 + 6 = 133(10) = 10000101(2)

M = 111 0110 1110 1001 0111 1001 (省略了最高数字位1, 23bit)

   组合起来就是:

                                M

       10000101      111 0110 1110 1001 0111 1001

   4bit一间隔:

0100   0010   1111   0110   1110   1001   0111   1001

                   F                                               9

 

转载自: http://blog.163.com/laorenyuhai126@126/blog/static/193507792010103104341148/

 

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------

 

最为一个常识,我们都知道浮点型在内存中占用的是4个字节的空间,而long型占用的是8个字节的空间。可是为什么4个字节的float型的最大值会大于long型的最大值呢?

       我们都知道,float类型的范围是:一3.403E38~3.403E38。而long类型的范围是:-2^63~2^63-1(大概是9*10^18)。

       我以前也是简单的记住就算完事了,对于它为什么会这样却没有考虑过。

 

       下面给大家分享一下我现在的理解:

         long整型数,在内存中占用8个字节共64位,它表示的数值有264次方,平分正负,数值范围是负263次方到正263次方-1

    而float在内存中占4个字节,共32位,但是浮点数在内存中是这样的:

        V=(-1)^s * M * 2^E

 

    浮点数的32位不是简单的直接表示大小,而是按照一定的标准分配的。

    其中第1位,符号位,即S

    接下来的8位,指数域,即E

    剩下的23位,小数域,即MM的取值范围为[12)或[01)。

    也就是说,浮点数在内存中的二进制值不是直接转换为十进制数值的,而是按照上述公式计算而来,通过这个公式,虽然只用到了4个字节,但是浮点数却比长整型的最大值要大。

 

    这也就是为什么在数据转换的时候,long类型转换为float类型的根本原因所在!

 

 

转载自:http://blog.csdn.net/lbq613613/article/details/7896621

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值