浮点数与IEEE浮点标准IEEE 浮点数格式中学到,单精度浮点数的表示格式为:


长度 32位,从高到低

符号 1

指数 8 (指数偏移 127)

尾数 23

有效位数 24(有1个隐含位
)


单精度浮点数

IEEE 754 标准所定义的单精度浮点数的长度为 32 位,按位域可划分为:符号位、阶码位与尾数位,如下:
  31----------------------22---------------------------------------------------------0
  |                       |                                                          |
  X X X X    X X X X    X X X X    X X X X    X X X X    X X X X    X X X X    X X X X
  | |-------------------| |----------------------------------------------------------|
符号        阶码                                     尾数

因此,用下面的代码就可以把各部分取出

#include <iostream>
#include <bitset>
#include <cstdio>
#include <cmath>
typedef struct FLOAT_SINGLE
{
    unsigned __int32 nFraction3 : 8;
    unsigned __int32 nFraction2 : 8;
    unsigned __int32 nFraction1 : 7;

    unsigned __int32 nExponent :  8;

    unsigned __int32 nSign     :  1;

} FP_SINGLE;
int explain_float(float a)
{
FLOAT_SINGLE* p = (FLOAT_SINGLE*)&a;

printf("浮点数 %f\t",a);

//printf("整数 %0X\t",(int&)a);

std::cout <<"二进制" << std::bitset<sizeof(int)*8>((int&)a) <<'\t';

printf("符号: %d\t", p->nSign );

printf("指数: %d\t", p->nExponent - 127 );       // 注意要减去偏移

printf("尾数p1: %f\t", p->nFraction1 /128.0 +1);

printf("尾数p2: %f\t", p->nFraction2 /256.0/128.0);

printf("尾数p3: %f\t", p->nFraction3 /256.0/256.0/128.0);

double d=p->nFraction1 /128.0 +1 + p->nFraction2 /256.0/128.0 + p->nFraction3 /256.0/256.0/128.0;
printf("尾数: %lf\t", d);
printf("计算数: %lf\n", (p->nSign==0?1:-1)*pow(2,p->nExponent - 127)*d);
}
int main()
{ 

explain_float(0); 

explain_float(1); 

explain_float(0.25); 

explain_float(0.75); 

explain_float(6); 

explain_float(128); 

explain_float(-123.456);
}

这就是下面代码能求2的正整数次幂的二进制1的位置的原理。只需要把指数部分提取出来就行了。

int ilog2(int a)
{
    float x=a;
    unsigned int ix = (unsigned int&)x;
    unsigned int exp = (ix >> 23) & 0xFF;
    int log2 = int(exp) - 127;

    return log2;
}

前面的结构把尾数拆分了,下面这个更简明

#include <cstdio>
#include <cmath>
typedef struct FLOAT_SINGLE
{
    unsigned __int32 nFraction : 23;

    unsigned __int32 nExponent :  8;

    unsigned __int32 nSign     :  1;

} FP_SINGLE;
int explain_float(float a)
{
FLOAT_SINGLE* p = (FLOAT_SINGLE*)&a;

printf("浮点数 %f\t",a);

printf("符号: %d\t", p->nSign );

printf("指数: %d\t", p->nExponent - 127 );       // 注意要减去偏移

printf("底数: %f\n", p->nFraction*1.0/(1<<23) +1);

printf("计算数: %f\n", pow(2,p->nExponent - 127)*(p->nFraction*1.0/(1<<23) +1));

}

这种方法还适合于非x86的小端系统,如arm。如下图所示。
手机c4droid的运行结果

说明:代码中的"底数"术语错误,应该是“尾数”.