假设代表IEEE 754浮点数的32位,如何使用表示上的整数或位操作(而不是使用机器指令或编译器操作来转换)将数字转换为整数? / p>
我有以下功能,但在某些情况下失败了:
输入: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;
答案 0 :(得分: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);
答案 1 :(得分:7)
&x
给出了x的地址,因此float*
类型。
(int*)&x
将指针强制转换为指向int
的指针,即指向int*
的指针。
*(int*)&x
取消引用指向int
值的指针。在int
和float
具有不同尺寸的机器上,它不会对您所信任的内容产生影响。
可能存在字节序问题。
此解决方案用于fast inverse square root算法。
答案 2 :(得分:7)
(有人应该仔细检查这个答案,尤其是边界情况和负值的四舍五入。另外,我把它写成舍入到最接近。为了重现C的转换,这应该改为舍入为零。 )
基本上,这个过程是:
将32位分成一个符号位( s ),八个指数位( e )和23个有效位( f ) 。我们将这些视为二进制补码整数。
如果 e 为255,则浮点对象为无穷大(如果 f 为零)或NaN(否则为)。在这种情况下,无法执行转换,应报告错误。
否则,如果 e 不为零,则将 24 添加到 f 。 (如果 e 不为零,则有效数字在其前面隐含有1位。添加2 24 使该位在 f 中显式。)
从 e 中减去127。 (这将指数从其偏置/编码形式转换为实际指数。如果我们正在进行任何值的一般转换,我们将不得不处理 e 为零时的特殊情况:减去126而不是但是,由于我们只转换为整数结果,我们可以忽略这种情况,只要这些微小输入数的整数结果为零。)
如果 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 向右移动,我们可能需要对其进行舍入,以便将结果四舍五入到最接近的整数。
如果 e 大于24,则将 f 左移 e -24位。返回 f 作为结果。
如果 e 小于-1,则浮点数介于-½和½之间,不包括。结果返回0.
否则,我们将 f 右移24- e 位。但是,我们将首先保存舍入所需的位数。将 r 设置为将f转换为无符号32位整数并将其向左移位32-(24- e )位的结果(等效地,将其左移8+ < em> e 位)。这将取出将从 f (下方)移出的位,并在32位中“左侧调整”它们,因此我们在它们开始时有一个固定的位置。
将 f 右移24- e 位。
如果 r 小于2 31 ,则不执行任何操作(这是向下舍入;移位截断位)。如果 r 大于2 31 ,请在 f 中添加一个(这是向上舍入的)。如果 r 等于2 31 ,则将 f 的低位添加到 f 。 (如果 f 是奇数,则在 f 中添加一个。在两个相等接近的值中,这将舍入为偶数值。)返回 f 。
答案 3 :(得分:1)
你不能(有意义地)以这种方式将浮点数转换为'整数'(signed int
或int
)。
它可能最终具有整数类型,但它实际上只是IEEE754编码空间的索引,本身并不是一个有意义的值。
您可能会认为unsigned
int作为位模式和整数值具有双重用途,但int
没有。
还有platform issues对位符号进行位操作。
答案 4 :(得分:1)
float x = 43.133;
int y;
assert (sizeof x == sizeof y);
memcpy (&y, &x, sizeof x);
...
答案 5 :(得分:1)
// 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);
答案 6 :(得分:-1)
您可以使用引用强制转换浮点数。像这样的演员应该永远不会生成任何代码。
C ++
float f = 1.0f;
int i = (int &)f;
printf("Float %f is 0x%08x\n", f, i);
输出:
Float 1.000000 is 0x3f800000
如果你想要c ++样式转换,请使用reinterpret_cast,就像这样。
int i = reinterpret_cast<int &>(f);
它不适用于表达式,您必须将其存储在变量中。
int i_times_two;
float f_times_two = f * 2.0f;
i_times_two = (int &)f_times_two;
i_times_two = (int &)(f * 2.0f);
main.cpp:25:13: error: C-style cast from rvalue to reference type 'int &'