浅谈浮点数

作者:冯建,华清远见嵌入式学院讲师。

浮点型变量在计算机内存中占用4字节(Byte),即32-bit。遵循IEEE-754格式标准。

一个浮点数由2部分组成:底数m 和 指数e。

±mantissa × 2exponent(注意,公式中的mantissa 和 exponent使用二进制表示)

底数部分 使用2进制数来表示此浮点数的实际值。

指数部分 占用8-bit的二进制数,可表示数值范围为0-255。 但是指数应可正可负,所以IEEE规定, 此处算出的次方须减去127才是真正的指数。所以float的指数可从 -126到128。

底数部分实际是占用24-bit的一个值,由于其最高位始终为 1 ,所以最高位省去不存储,在存储中只有23-bit。

到目前为止, 底数部分 23位 加上指数部分 8位 使用了31位。那么前面说过,float是占用4个字节即 32-bit,那么还有一位是干嘛用的呢? 还有一位,其实就是4字节中的最高位,用来指示浮点数的正负,当最高位是1时,为负数,最高位是0时,为正数。

浮点数据就是按下表的格式存储在4个字节中:

Address+0 Address+1 Address+2 Address+3
        Contents SEEE EEEE EMMM MMMM MMMM MMMM MMMM MMMM
        S: 表示浮点数正负,1为负数,0为正数
        E: 指数加上127后的值的二进制数
        M: 24-bit的底数(只存储23-bit)

注意:这里有个特例,浮点数 为0时,指数和底数都为0,但此前的公式不成立。因为2的0次方为1,所以0是个特例。当然,这个特例也不用认为去干扰,编译器会自动去识别。

通过上面的格式,我们下面举例看下-12.5在计算机中存储的具体数据:

Address+0 Address+1 Address+2 Address+3
        Contents 0xC1 0x48 0x00 0x00

接下来我们验证下上面的数据表示的到底是不是-12.5,从而也看下它的转换过程。

由于浮点数不是以直接格式存储,他有几部分组成,所以要转换浮点数,首先要把各部分的值分离出来。

        Address+0 Address+1 Address+2 Address+3
                格式 SEEEEEEE EMMMMMMM MMMMMMMM MMMMMMMM
                二进制 11000001 01001000 00000000 00000000
                16进制 C1 48 00 00
        可见:
                S: 为1,是个负数。
                E:为 10000010 转为10进制为130,130-127=3,即实际指数部分为3.
                M:为 10010000000000000000000。

这里,在底数左边省略存储了一个1,使用实际底数表示为 1.10010000000000000000000 。

现在,我们通过指数部分E的值来调整底数部分M的值。调整方法为:如果指数E为负数,底数的小数点向左移,如果指数E为正数,底数的小数点向右移。小数点移动的位数由指数E的绝对值决定。

这里,E为正3,使用向右移3为即得:1100.10000000000000000000。

至次,这个结果就是12.5的二进制浮点数,将他换算成10进制数就看到12.5了,如何转换,看下面:

小数点左边的1100 表示为 (1 × 23) + (1 × 22) + (0 × 21) + (0 × 20), 其结果为 12 。

小数点右边的 .100… 表示为 (1 × 2-1) + (0 × 2-2) + (0 × 2-3) + ... ,其结果为.5 。

以上二值的和为12.5, 由于S 为1,使用为负数,即-12.5 。

所以,16进制 0XC1480000 是浮点数 -12.5 。

上面是如何将计算机存储中的二进制数如何转换成实际浮点数,下面看下如何将一浮点数装换成计算机存储格式中的二进制数。

举例将17.625换算成 float型。

首先,将17.625换算成二进制位:10001.101 ( 0.625 = 0.5+0.125, 0.5即 1/2, 0.125即 1/8 如果 不会将小数部分转换成二进制,请参考其他书籍。) 再将 10001.101 向右移,直到小数点前只剩一位 成了 1.0001101 x 2的4次方 (因为右移了4位)。此时 我们的底数M和指数E就出来了:

底数部分M,因为小数点前必为1,所以IEEE规定只记录小数点后的就好,所以此处底数为 0001101 。

指数部分E,实际为4,但须加上127,固为131,即二进制数 10000011

符号部分S,由于是正数,所以S为0。

综上所述,17.625的 float 存储格式就是:0 10000011 00011010000000000000000

转换成16进制:0x41 8D 00 00

所以,一看,还是占用了4个字节。

接下来看存储:

Float数据结构:
                【S】【30——Exp——23】【22——Frac——0】

Double数据结构:
                【S】【62——Exp——52】【51——Frac——0】
        S: Sign bit 符号位
        Exp: exponent(bias) 指数(偏移)
        Frac: fraction 有效位数

Exp在公式中是2的幂,接近零的小数的描述应为有符号数,有符号数的表示可以为符号位+数字位、补数等,IEEE754采用的是偏移法,不作过多解释。

对Float偏移量为0x7F(127)、Double偏移量为0x3FF(1023)。

Frac便是有效位数,

注释 浮点值 S Exp Frac 数学值
        -----------------------------------------------------------------------
        零 0x00000000 0 0x00 0B000...000 0.0
        -----------------------------------------------------------------------
        Min正次正规数 0x00000001 0 0x00 0B000...001 1.40129846e^-45
        Max正次正规数 0x007FFFFF 0 0x00 0B111...111 1.17549421e^-38
        -----------------------------------------------------------------------
        Min正正规数 0x00800000 0 0x01 0B000...000 1.17549435e^-38
        Max正正规数 0x7F7FFFFF 0 0xFE 0B111...111 3.40282347e^+38
        -----------------------------------------------------------------------
        Not a Number 0xXXXXXXXX x 0xFF 0Bxxx...xxx NaN是一个数族
        正无限 0x7F800000 0 0xFF 0B000...000 +Inf
        负无限 0xFF800000 1 0xFF 0B000...000 -Inf

首先举例求Float_Max正正规数:

Exp =0xFE = 254;
         Frac=(2^23 - 1)
        代入: 2^127 * (1 + (2^23-1) * 2^-23)
        = 2^128 - 2^104
        = 3.4028e+38

其它的可自己求。

所以float 型的幂是38,Double的幂应该是308。

嵌入式及3G相关资源及学习请点击:嵌入式开发视频 android开发视频 android培训 3G培训 QT培训 QT开发视频 物联网培训 物联网技术视频 嵌入式学习 

阅读更多
想对作者说点什么? 我来说一句

浅谈OFBIZ.doc

2009年07月07日 930KB 下载

非常棒的缓存技术教程

2011年03月30日 471KB 下载

浅谈CSRF攻击方式

2011年03月09日 295KB 下载

ERP\erp浅谈ERP\erp浅谈

2010年07月16日 2.19MB 下载

没有更多推荐了,返回首页

不良信息举报

浅谈浮点数

最多只允许输入30个字

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭