否则c中的浮点数在某些情况下会失败

时间:2012-09-09 05:10:13

标签: c bit-manipulation

我编写了一个适用于数百个案例的函数,但在某些情况下失败了。

这是C函数:

unsigned negate_number(unsigned x) {
  int sign = (!(x & 0x80000000))<<31;
  int other = 0x7FFFFFFF & x;
  return (sign | other);
}

我只是屏蔽标志,反转它并与蒙面指数和mantessa进行OR(加入)。所以这应该适用于所有情况。

但是这是一个失败的情况: x = 0x7fc00000(2143289344)

1 个答案:

答案 0 :(得分:1)

我问道:

  

当代码使用整数时,为什么要询问标题中的“浮点数”?您是否尝试使用float调用该函数并将其视为一个位数组,或多或少?如果是这样的话,那你就隐藏起来了!如果使用范围内的原型调用函数,C编译器会将float转换为unsigned int。如果你没有在范围内用原型调用它,C编译器会在调用函数之前将float转换为double

答案是:

  

这是一个32位IEEE 754单精度数。所以我只是翻转最重要的位(符号位)。

要翻转32位(无符号整数)数量的最高位,您可以简单地写:

x ^= 0x80000000;

但是,正如我所指出的那样,除非你对编译器说谎,否则你根本就没有通过32位float。如果你有:

,你可以“让它工作”(在某些机器上,某些时候)

虚假代码

fileA.c

extern float negate_number(float x);

...
float f1 = 3.14159;
float f2 = negate_number(f1);
...

fileB.c

unsigned negate_number(unsigned x)
{
    return x ^ 0x80000000;
}

然而,你正在玩你的编译器。编译器讨厌被骗,并经常找到一种方法来获得自己的回报。 不要这样做!

主要是犹太密码

要以最少的问题(但不是“没有问题”)或多或少地达到你想要的效果,你可能需要:

fileB.c

float negate_number(float f)
{
    union { unsigned x; float y; } u;
    u.y = f;
    u.x ^= 0x80000000;
    return u.y;
}

严格地说,在分配给u.x之后读取和写入u.y是未定义的行为,但它通常会按照您的意愿行事;类似于在操纵u.y之后返回u.x

所有这些假设floatunsigned的位布局使得float的符号位是unsigned的最高位。< / p>