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)
(有人应该仔细检查这个答案,特别是边界情况和负值的四舍五入.另外,我把它写成舍入到最接近.为了重现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.
float x = 43.133;
int y;
assert (sizeof x == sizeof y);
memcpy (&y, &x, sizeof x);
...
Run Code Online (Sandbox Code Playgroud)
// 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)