【问题标题】:Getting the exponent from a floating point in C从C中的浮点获取指数
【发布时间】:2015-12-16 00:50:21
【问题描述】:

我正在编写一个函数,它将获取浮点数(IEEE 754 标准)的指数,但由于某种原因,当我对返回的数字使用右移位运算符时,它返回 0

这里是函数

int get_exp (int x) 
{
  return ( ((x >> 21) & 255) -127 ); 
}

我将它传递给 7.23,所以输出应该是 2,由于某种原因, (x >> 21) 部分在它实际上应该返回 129 时返回 0。255 是我用来和 (& ) 与浮点数的指数部分。

【问题讨论】:

  • 邮政编码示例“我通过了 7.23”
  • 为什么上面的代码右移了21而不是23位?

标签: c floating-point numbers exponent


【解决方案1】:

我猜你正在做某种类型的投射骗局以将浮点作为ints 传递?我会使用<math.h> 中定义的float frexpf (float x, int* exp);

#include <math.h>

int get_exp(float x) 
{
    int exp;
    frexpf(x, &exp);
    return exp; 
}

无论浮点类型的大小如何,它都能保证工作。

如果你想自己滚动,你可以修改这段代码。

#define EXPONENT_BIAS (-127)

int get_exp(float f) 
{
    int i;
    union {
        // Set here, then use s or c to extract
        float f;
        // This may or may not work for you
        struct {
            unsigned int sign: 1;
            unsigned int exponent: 8;
            unsigned int mantissa: 23;
        } s;
        // For debugging purposes
        unsigned char c[sizeof(float)];
    } u;

    // Assign, you might need to reverse the bytes!
    u.f = f;

    // You'll probably need this to figure out the field widths
    for (i = 0; i < sizeof(float); i++)
        fprintf(stderr, "%02x%s", u.c[i], (i + 1 < sizeof(float))? " ": "\n");

    // Just return the exponent
    return (int)u.s.exponent + EXPONENT_BIAS;
}

如果sizeof(float) != 4,或者如果你切换字节序,这会咬你。

【讨论】:

  • 我必须在不使用任何已定义函数的情况下这样做
  • @Yimin Rong 有没有办法不用freexp?
  • static_assert(sizeof(float)==4,"Implementation error!");
  • 注意:这两种方法(都是正确的)由于有效数/尾数范围的不同想法而存在差异。
【解决方案2】:

假设 float 是 32 位并且布局为 as specified here,您会遇到三个问题:

  • 您的函数需要接受float
  • 您需要将uint32_t 指向float 的地址,以便它看到相同的字节,然后针对取消引用的指针执行操作。
  • 指数从第 24 位(如果从 0 开始,则为 23)位开始,而不是从第 22 位(如果从 0 开始,则为 21),因此您必须移动 23。

#include <stdio.h>
#include <stdint.h>

int get_exp (float x)
{
  uint32_t *i = (uint32_t *)&x;
  return ( ((*i >> 23) & 255) -127 );
}

int main()
{
    printf("exp=%d\n",get_exp(7.23));
}

结果:

exp=2

【讨论】:

  • @KareemYoussef 不能,否则有问题的数字将不是 IEE 754 浮点格式。除非您从字节数组中手动​​构造它,否则不会。
【解决方案3】:

如果性能不是问题,只需迭代:

int expof(float f) {
  int expo = 0;
  if (f < 0.0) f = -f;
  while (f < 0.5f) {
    f *= 2.0f;
    expo--;
  }
  while (f >= 1.0f) {
    f *= 0.5f;
    expo++;
  }
  return expo;
}

不依赖于任何特定的float 实现,除了指数适合int。正如here 所评论的那样,它不使用任何外部函数。

int expo; frexpf(f, &amp;expo); return expo的结果相同

【讨论】:

    【解决方案4】:

    主要问题是传递 int 而不是 float 并使用 21 与 23。@dbush

    IEEE 754 标准 (binary32) 有许多极端情况:Inifinty、NaN、包括零在内的次正规。所以需要额外的代码来处理它们。

    假设正确的字节序:

    int get_exp(float x) {
      assert(sizeof x == sizeof(uint32_t));
      union {
        float x;
        uint32_t u32;
      } u = { x };
      #define EXPOSHIFT 23
      #define EXPOMASK 255
      #define EXPOBIAS 127
      if (x == 0.0) return 0;
      int expo = (int) (u.u32 >> EXPOSHIFT) & EXPOMASK;
      if (expo == EXPOMASK) return INT_MAX;  //  x is infinity or NaN
      if (expo == 0) return get_exp(x * (1L << EXPOSHIFT)) - EXPOSHIFT;
      return expo - EXPOBIAS;
    }
    

    【讨论】:

      【解决方案5】:

      参数列表显示

      int x
      

      然后你传递一个浮点数。尝试替换为

      float x
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-03-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多