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

Met*_*est 41 c floating-point emulation

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

我需要首先在处理器上提取浮点数的符号,尾数和指数,它们支持浮点数.所以,我的问题是如何获得单个精度浮点数的符号,尾数和指数.

按照这个图的格式,

在此输入图像描述 这就是我到目前为止所做的,但除了符号,尾数和指数都不正确.我想,我错过了一些东西.

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;
}
Run Code Online (Sandbox Code Playgroud)

Pie*_*one 25

我的建议是坚持使用规则0而不是重做已经做过的标准库,如果这足够的话.查看math.h(标准C++中的cmath)和函数frexp,frexpf,frexpl,它们在其有效数和指数部分中打破浮点值(double,float或long double).要从有效数字中提取符号,您可以使用signbit,也可以使用math.h/cmath或copysign(仅限C++ 11).一些替代方案,语义不同,是modf和ilogb/scalbn,可在C++ 11中找到; http://en.cppreference.com/w/cpp/numeric/math/logb比较它们,但我没有在文档中找到所有这些函数如何使用+/- inf和NaNs.最后,如果你真的想使用位掩码(例如,你迫切需要知道确切的位,并且你的程序可能有不同的NaN具有不同的表示,并且你不相信上述函数),至少使所有东西都与平台无关通过使用float.h/cfloat中的宏.


Ale*_*nze 20

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

或者,您可以使用本答案中所示的一些特殊功能(double frexp(double value, int *exp);double ldexp(double x, int exp);)来获取这些部件.

另一种选择是使用%aprintf().


era*_*ran 20

我认为使用工会做演员表会更好,但更清楚.

#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);
}
Run Code Online (Sandbox Code Playgroud)

示例基于 http://en.wikipedia.org/wiki/Single_precision

  • 当1)`float`不是IEEE 754 32位二进制(不那么罕见)时,此方法失败2)`unsigned`是16位(在嵌入式世界中很常见)3)`unsigned/float`的endian不匹配.(罕见).4)数学解释用于"指数/尾数",因为这个答案显示了偏差指数和不完整的有效数/尾数. (10认同)
  • 这里的聚会很晚,但不是,'联盟'并不是更好,因为它根本不能保证工作.它当然不便携.没有什么约束C实现来布局位域,使得联合将它们映射到所谓的"浮动"表示的部分,尽管依赖于类型惩罚的单独问题. (7认同)
  • 没有法律规定你必须只使用它们最初创建的东西.否则第一架飞机就不会使用自行车."一般"未定义?如果定义了这种情况,或者对某个特定平台/情况下的行为感到满意,那会怎么样? (6认同)
  • "出于某种原因,联盟的这个原始目的得到了"覆盖"与完全不同的东西:写一个联盟的一个成员,然后通过另一个成员检查它.这种记忆重新解释不是对工会的有效使用.未定义的行为." http://stackoverflow.com/a/2313676/1127387 (3认同)
  • 以上代码是否可移植?在大型和小型端机器上会发生什么? (2认同)
  • 但是`uint32_t`可能更好地指定一个不超过4个字节的位字段. (2认同)

Xym*_*ech 8

&错了.我想你想要:

s = *ptr >> 31;
e = *ptr & 0x7f800000;
e >>= 23;
m = *ptr & 0x007fffff;
Run Code Online (Sandbox Code Playgroud)

记住,当你&,你正在将你没有设置的位清零.因此,在这种情况下,您希望在获得指数时将符号位清零,并且希望在获得尾数时将符号位和指数置零.

请注意,面具直接来自您的照片.因此,指数掩码将如下所示:

0 11111111 00000000000000000000000

并且尾数掩码看起来像:

0 00000000 11111111111111111111111

  • 那么所谓的隐藏位呢?我没有看到有人设置它:`m | = 0x00800000;`.请注意,应首先检查数字的特殊值(非正规,NaN,无穷大),因为这些需要不同的处理. (3认同)

Max*_*kin 6

在Linux包上,glibc-headers提供了#include <ieee754.h>带浮点类型定义的头,例如:

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.  */
Run Code Online (Sandbox Code Playgroud)