在C中将float转换为int(按位)

Ano*_*ous 13 c floating-point bit-manipulation bitwise-operators

给定代表IEEE 754浮点数的32位,如何使用表示上的整数或位操作(而不是使用机器指令或编译器操作进行转换)将数字转换为整数?

我有以下功能,但在某些情况下失败:

输入:int x(包含IEEE 754格式的32位单精度数)

  if(x == 0) return x;

  unsigned int signBit = 0;
  unsigned int absX = (unsigned int)x;
  if (x < 0)
  {
      signBit = 0x80000000u;
      absX = (unsigned int)-x;
  }

  unsigned int exponent = 158;
  while ((absX & 0x80000000) == 0)
  {
      exponent--;
      absX <<= 1;
  }

  unsigned int mantissa = absX >> 8;

  unsigned int result = signBit | (exponent << 23) | (mantissa & 0x7fffff);
  printf("\nfor x: %x, result: %x",x,result);
  return result;
Run Code Online (Sandbox Code Playgroud)

小智 20

C有"联合"来处理这种类型的数据视图:

typedef union {
  int i;
  float f;
 } u;
 u u1;
 u1.f = 45.6789;
 /* now u1.i refers to the int version of the float */
 printf("%d",u1.i);
Run Code Online (Sandbox Code Playgroud)

  • 由于C99,@ TLW类型通过联合的惩罚不是UB.例如,在N1256 6.5.2.3脚注82中明确提到了这一点. (11认同)
  • 在我所知道的每个 C 标准中,这都是未定义的行为。 (3认同)

Bas*_*tch 8

&x给出x的地址,所以有float*类型.

(int*)&x将指针转换为指向intie 的指针int*.

*(int*)&x取消引用指针到一个int值.它不会对你所拥有intfloat不同尺寸的机器产生什么影响.

并且可能存在字节序问题.

该解决方案用于快速平方根算法.


Eri*_*hil 7

(有人应该仔细检查这个答案,特别是边界情况和负值的四舍五入.另外,我把它写成舍入到最接近.为了重现C的转换,这应该改为舍入为零.)

从本质上讲,这个过程是:

32位分离为一个符号位(小号),八个指数位(ë),和23个有效数位(˚F).我们将这些视为二进制补码整数.

如果e为255,则浮点对象为无穷大(如果f为零)或NaN(否则为).在这种情况下,无法执行转换,应报告错误.

否则,如果e不为零,则向f添加2 24.(如果e不为零,则有效数字在其前面隐含有1位.添加2 24会使该位在f中显式.)

e减去127 .(这将指数从其偏置/编码形式转换为实际指数.如果我们正在进行任何值的一般转换,我们将不得不处理e为零时的特殊情况:减去126而不是127.但是,因为我们只转换为整数结果,我们可以忽略这种情况,只要这些微小输入数的整数结果为零.)

如果s为0(符号为正)且e为31或更大,则该值溢出带符号的32位整数(它为2 31或更大).无法执行转换,应报告错误.

如果s为1(符号为负)且e大于31,则该值溢出带符号的32位整数(小于或等于-2 32).如果s是1,e是32,并且f大于2 24(设置了任何原始有效位数),则该值溢出有符号的32位整数(小于-2 31 ;如果原始f为零,它将正好是-2 31,不会溢出).在任何这些情况下,都无法执行转换,应报告错误.

现在我们有一个s,一个e和一个不会溢出的值的f,所以我们可以准备最终值.

如果s为1,则将f设置为-f.

指数值用于1(包括)和2(不包括)之间的有效数字,但是我们的有效数字从2 24开始.所以我们必须对此进行调整.如果e是24,我们的有效数字是正确的,我们就完成了,所以返回f作为结果.如果e大于24或小于24,我们必须适当地改变有效数.此外,如果我们要向右移动f,我们可能需要对其进行舍入,以将结果舍入为最接近的整数.

如果Ë大于24,移位˚Fë -24位.结果返回f.

如果e小于-1,则浮点数介于-½和½之间,不包括.结果返回0.

否则,我们将转向˚F右侧24 Ë位.但是,我们将首先保存舍入所需的位数.将r设置为将f转换为无符号32位整数并将其向左移位32-(24- e)位(相当于左移8 + e位)的结果.这将取出将从f(下方)移出的位,并在32位中"左移"调整它们,因此我们在它们开始时有一个固定的位置.

˚F右24 Ë位.

如果r小于2 31,则不执行任何操作(这是向下舍入;移位截断位).如果r大于2 31,则向f添加一个(这是向上舍入).如果r等于2 31,则将f的低位加到f.(如果f为奇数,则向f中加1.在两个相等的近似值中,这将舍入到偶数值.)返回f.


wil*_*ser 6

float x = 43.133;
int y;

assert (sizeof x == sizeof y);
memcpy (&y, &x, sizeof x);
...
Run Code Online (Sandbox Code Playgroud)


Din*_*ini 6

// With the proviso that your compiler implementation uses
// the same number of bytes for an int as for a float:
// example float
float f = 1.234f;
// get address of float, cast as pointer to int, reference
int i = *((int *)&f);
// get address of int, cast as pointer to float, reference
float g = *((float *)&i);
printf("%f %f %08x\n",f,g,i);
Run Code Online (Sandbox Code Playgroud)

  • 我不同意。这是一个很好的独立示例,Brucher 先生,声誉为 6,923 (2认同)
  • 这是否违反了严格的别名规则? (2认同)

Ale*_*own -1

您不能(有意义地)以这种方式将浮点数转换为“整数”(signed int或)。int

它最终可能是整数类型,但它实际上只是 IEEE754 编码空间的索引,本身并不是一个有意义的值。

您可能会认为unsignedint 有双重用途:位模式和整数值,但int事实并非如此。


此外,还有符号整数的位操作的平台问题。

  • 有意义的用途:在总线上接收两个“int16_t”,它们实际上代表一个“float32”。将两个“int16_t”重新解释为浮点数。 (7认同)