仅使用按位操作将float转换为int(float2int)

时间:2013-12-02 00:11:36

标签: c assembly floating-point integer arm

我想知道是否有人可以让我在正确的方向上解决我正在处理的问题。我试图只使用ARM程序集和位操作执行以下C函数:

int float2int(float x) {
return (int) x;
}

我已经编写了这个(int2float)的反面而没有太多问题。我只是不确定从这个新问题的起点。

例如:

3 (int) = 0x40400000 (float) 
0011 = 0 10000000 10000000000000000000000

其中0是符号位,10000000是指数,10000000000000000000000是尾数/分数。

有人可以简单地指出我正确的方向吗?即使是C伪代码表示也会有所帮助。我知道我需要提取符号位,提取指数并反转偏差(127)并提取分数但我不知道从哪里开始。

还有一个问题,即浮点数不能表示为整数(因为它溢出或是NaN)。

任何帮助将不胜感激!

3 个答案:

答案 0 :(得分:1)

// Assume int can hold all the precision of a float.
int float2int(float x) {
  int Sign = f_SignRawBit(x);
  unsigned Mantissa = f_RawMantissaBits(x);  // 0 - 0x7FFFFF
  int Expo = f_RawExpoBits(x); // 0 - 255
  // Form correct exponent and mantissa
  if (Expo == EXPO_MAX) {
    Handle_NAN_INF();
  }
  else if (Expo == EXPO_MIN) {
    Expo += BIAS + 1 - MantissaOffset /* 23 */;
  }
  else {
    Expo += BIAS - MantissaOffset /* 23 */;
    Mantissa |= ImpliedBit;
  }
  while (Expo > 0) {
    Expo--;
    // Add code to detect overflow
    Mantissa *= 2;
  }
  while (Expo < 0) {
    Expo++;
    // Add code to note last shifted out bit
    // Add code to note if any non-zero bit shifted out
    Mantissa /= 2;
  }

  // Add rounding code depending on `last shifted out bit` and `non-zero bit shifted out`.  May not be need if rounding toward 0.

  // Add code to detect over/under flow in the following
  if (Sign) {
    return -Mantissa;
  }
  return Mantissa;
}

答案 1 :(得分:1)

从一个数字开始,其尾数是您的数字(在您的示例中为00000011),其指数为01111111127,这是0存储在超过127的数字) 计算从LSb到最后设置位(未包括)的位数。对于计算的每个位,将1加到指数中。

在您的示例中:从LSb到最后一个(最高有效)位集只有一位,因此指数加1,结果为128(10000000)。

左移你的尾数(原始数字),使最左边的设置位丢失。考虑到必须使用能够保持至少23位的变量来执行移位。因此,在您的示例中,原始尾数为00000000000000000000011。你必须向左移动直到最左边的'1'丢失,导致10000000000000000000000 关于标志,如果原始数字是2补码,只需拿MSb,这将是你的标志。在您的示例中,0(正)

所以你的结果将是: Sign : 0 Exponent: 10000000 Mantissa: 10000000000000000000000

另一个例子:将短整数-234转换为浮点数。 使用2补码的-234存储为1111111100010110(16位)

从这里可以轻松获得标志:1(MSb)

我们必须使用绝对幅度,所以我们补充数字以得到正(幅度)版本。我们可以通过使用1111111111111111对其进行评分,然后添加1.这样就可以了解0000000011101010(234)

初始尾数(使用23位):00000000000000011101010 初始指数:01111111(127) 计算从LSb到最左侧设置位的位数,不包括它。有7位。我们将此添加到我们的指数中:127+7=134 = 10000110 尾数向左移动,直到最左侧的设置位消失。这给了我们: 11010100000000000000000

我们的号码是:1 10000110 11010100000000000000000

答案 2 :(得分:1)

以下是一些用于转换的基本C ++代码。

#include <stdint.h>

union IntFloat
{
    uint32_t i;
    float    f;
};

int32_t Float32ToInt24( const float & x )
{
    IntFloat n;
    n.f = x;

    uint8_t  negative = ((n.i >> 31) & 0x1        )            ; // 0x10000000
    uint8_t  exponent = ((n.i >> 23) &  0xFF      )            ; // 0x7F800000
    uint32_t mantissa = ((n.i >>  0) &    0x7FFFFF) | 0x800000 ; // 0x007FFFFF implicit bit
    int32_t  i        = mantissa >> (22 - (exponent - 0x80));
    if( !exponent )
        return 0;
    if( negative )
        return -i;
    else
        return  i;
}

注意:浮点数大于2 ^ 24将无法正确转换为整数,因为尾数只有24位精度。即添加两个浮点数16777216.0 + 1.0将无效!