C 如何获取浮点数的符号、尾数和指数

C 如何获取浮点数的符号、尾数和指数,c,floating-point,emulation,C,Floating Point,Emulation,我有一个程序,它运行在两个处理器上,其中一个不支持浮点运算。所以,我需要在处理器中使用定点执行浮点计算。为此,我将使用浮点仿真库 我需要首先在支持浮点运算的处理器上提取浮点数的符号、尾数和指数。所以,我的问题是如何得到单精度浮点数的符号、尾数和指数 按照此图的格式 这就是我到目前为止所做的,但除了符号,尾数和指数都不正确。我想,我错过了一些东西 void getSME( int& s, int& m, int& e, float number ) { unsig

我有一个程序,它运行在两个处理器上,其中一个不支持浮点运算。所以,我需要在处理器中使用定点执行浮点计算。为此,我将使用浮点仿真库

我需要首先在支持浮点运算的处理器上提取浮点数的符号、尾数和指数。所以,我的问题是如何得到单精度浮点数的符号、尾数和指数

按照此图的格式

这就是我到目前为止所做的,但除了符号,尾数和指数都不正确。我想,我错过了一些东西

void getSME( int& s, int& m, int& e, float number )
{
    unsigned int* ptr = (unsigned int*)&number;

    s = *ptr >> 31;
    e = *ptr & 0x7f800000;
    e >>= 23;
    m = *ptr & 0x007fffff;
}

将指向浮点变量的指针强制转换为类似于
无符号int
。然后,您可以移动和屏蔽位以获得每个组件

float foo;
unsigned int ival, mantissa, exponent, sign;

foo = -21.4f;
ival = *((unsigned int *)&foo);
mantissa = ( ival & 0x7FFFFF);
ival = ival >> 23;
exponent = ( ival  & 0xFF );
ival = ival >> 8;
sign = ( ival & 0x01 );

显然,您可能不会对指数位和符号位使用无符号整数,但这至少会给您一个想法。

找出直接支持浮点的CPU上使用的浮点数的格式,并将其分解为这些部分。最常见的格式是

或者,您可以使用一些特殊函数(
double-frexp(double-value,int*exp);
double-ldexp(double-x,int-exp);
)获取这些部件,如中所示


是将
%a
printf()一起使用
我认为使用联合进行强制转换更好,更清晰

#include <stdio.h>

typedef union {
  float f;
  struct {
    unsigned int mantisa : 23;
    unsigned int exponent : 8;
    unsigned int sign : 1;
  } parts;
} float_cast;

int main(void) {
  float_cast d1 = { .f = 0.15625 };
  printf("sign = %x\n", d1.parts.sign);
  printf("exponent = %x\n", d1.parts.exponent);
  printf("mantisa = %x\n", d1.parts.mantisa);
}
#包括
typedef联合{
浮动f;
结构{
无符号整数mantisa:23;
无符号整数指数:8;
无符号整数符号:1;
}零件;
}浮雕;
内部主(空){
浮点数d1={.f=0.15625};
printf(“符号=%x\n”,d1.parts.sign);
printf(“指数=%x\n”,d1.parts.exponent);
printf(“mantisa=%x\n”,d1.parts.mantisa);
}

基于

的示例,您的
&
输入了错误的位。我想你想要:

s = *ptr >> 31;
e = *ptr & 0x7f800000;
e >>= 23;
m = *ptr & 0x007fffff;
请记住,当您
&
时,您正在将未设置的位归零。在这种情况下,当你得到指数时,你想把符号位置零,当你得到尾数时,你想把符号位和指数置零

请注意,遮罩直接来自您的图片。因此,指数掩码将如下所示:

0 11111110000000000000000000000000000

尾数面具看起来像:

00000000 11111111111111


我的建议是坚持规则0,如果这足够的话,不要重做标准库已经做的事情。看看math.h(标准C++中的cmath)和函数frexp、frexpf、frexpl,它们在有效位和指数部分中断浮点值(double、float或long double)。要从有效位提取符号,您可以使用signbit,也可以在math.h/cmath或copysign(仅限C++11)中使用。一些语义稍有不同的替代方案是modf和ilogb/scalbn,可在C++11中使用;比较了它们,但我在文档中没有找到所有这些函数在+/-inf和NAN中的行为。最后,如果您确实想使用位掩码(例如,您迫切需要知道确切的位,并且您的程序可能具有不同表示形式的不同NAN,并且您不信任上述函数),至少通过使用float.h/cfloat中的宏使所有内容独立于平台。

在Linux软件包中,glibc headers提供了带有浮点类型定义的header
#include
,例如:

union ieee754_double
  {
    double d;

    /* This is the IEEE 754 double-precision format.  */
    struct
      {
#if __BYTE_ORDER == __BIG_ENDIAN
    unsigned int negative:1;
    unsigned int exponent:11;
    /* Together these comprise the mantissa.  */
    unsigned int mantissa0:20;
    unsigned int mantissa1:32;
#endif              /* Big endian.  */
#if __BYTE_ORDER == __LITTLE_ENDIAN
# if    __FLOAT_WORD_ORDER == __BIG_ENDIAN
    unsigned int mantissa0:20;
    unsigned int exponent:11;
    unsigned int negative:1;
    unsigned int mantissa1:32;
# else
    /* Together these comprise the mantissa.  */
    unsigned int mantissa1:32;
    unsigned int mantissa0:20;
    unsigned int exponent:11;
    unsigned int negative:1;
# endif
#endif              /* Little endian.  */
      } ieee;

    /* This format makes it easier to see if a NaN is a signalling NaN.  */
    struct
      {
#if __BYTE_ORDER == __BIG_ENDIAN
    unsigned int negative:1;
    unsigned int exponent:11;
    unsigned int quiet_nan:1;
    /* Together these comprise the mantissa.  */
    unsigned int mantissa0:19;
    unsigned int mantissa1:32;
#else
# if    __FLOAT_WORD_ORDER == __BIG_ENDIAN
    unsigned int mantissa0:19;
    unsigned int quiet_nan:1;
    unsigned int exponent:11;
    unsigned int negative:1;
    unsigned int mantissa1:32;
# else
    /* Together these comprise the mantissa.  */
    unsigned int mantissa1:32;
    unsigned int mantissa0:19;
    unsigned int quiet_nan:1;
    unsigned int exponent:11;
    unsigned int negative:1;
# endif
#endif
      } ieee_nan;
  };

#define IEEE754_DOUBLE_BIAS 0x3ff /* Added to exponent.  */
  • 不要让函数做多种事情
  • 不要遮掩然后转移;先移位,然后遮罩
  • 不要不必要地改变值,因为它速度慢、缓存破坏和容易出错
  • 不要使用魔法数字
  • /*NaNs、无穷大、未处理的非规范化*/
    /*假设sizeof(float)==4,并使用ieee754二进制32格式*/
    /*假设两个s-补码机器*/
    /*C99*/
    #包括
    #定义符号(f)((f)有关要提取的联合类型,请参见此标题:
    float
    double
    long double
    ,(endianness handled)。以下是一个提取:

    /*
    ** - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    **  Single Precision (float)  --  Standard IEEE 754 Floating-point Specification
    */
    
    # define IEEE_754_FLOAT_MANTISSA_BITS (23)
    # define IEEE_754_FLOAT_EXPONENT_BITS (8)
    # define IEEE_754_FLOAT_SIGN_BITS     (1)
    
    .
    .
    .
    
    # if (IS_BIG_ENDIAN == 1)
        typedef union {
            float value;
            struct {
                __int8_t   sign     : IEEE_754_FLOAT_SIGN_BITS;
                __int8_t   exponent : IEEE_754_FLOAT_EXPONENT_BITS;
                __uint32_t mantissa : IEEE_754_FLOAT_MANTISSA_BITS;
            };
        } IEEE_754_float;
    # else
        typedef union {
            float value;
            struct {
                __uint32_t mantissa : IEEE_754_FLOAT_MANTISSA_BITS;
                __int8_t   exponent : IEEE_754_FLOAT_EXPONENT_BITS;
                __int8_t   sign     : IEEE_754_FLOAT_SIGN_BITS;
            };
        } IEEE_754_float;
    # endif
    
    有关如何将
    double
    值转换为字符串形式的演示,请参阅

    此外,请参阅的一节,它非常好地简单地解释了所有浮点类型的内存表示/布局,以及如何按照IEEE 754浮点规范对其进行解码(带插图)


    它还有指向真正优秀的资源的链接,这些资源的解释更深入。

    试着从这里开始:,但我几乎可以肯定的是,通过指针转换的别名在C标准中不受支持,在某些编译器中可能会很麻烦。最好使用
    (union{float f;uint32_t u;}{number}.u
    。这将返回一个
    uint32_t
    ,即
    float
    number
    的字节,重新解释为32位无符号整数。我假设IEEE 754为32位二进制。您是否注意到以下问题?(1)通过将127添加到实际指数,对指数进行了偏置。(2)除了非常小的浮点,所有的都是标准化的,并且标准化浮点尾数的前导1位不被存储。你是指C还是C++(C没有引用,只有指针)三个问题:0。没有从编码的指数1中移除偏差。没有为正常的非零数添加隐式尾数2。没有处理非规范、无穷和sNaN/qNaNs。我知道,这就是我所做的,但我没有得到正确的值。请参阅我编辑的帖子。未定义behaviour@MetallicPriest现在试试,我第一次戴错面具了时间。那么所谓的隐藏位呢?我没有看到任何人设置它:
    m |=0x00800000;
    。请注意,应该检查数字是否有特殊值(非规范、NaN、无穷大)首先,因为这些需要不同的处理方法。@RudyVelthuis来自他们的原始代码,看起来他们并没有试图实际获得指数和ma的值