我编写了一个适用于数百个案例的函数,但在某些情况下失败了。
这是C函数:
unsigned negate_number(unsigned x) {
int sign = (!(x & 0x80000000))<<31;
int other = 0x7FFFFFFF & x;
return (sign | other);
}
我只是屏蔽标志,反转它并与蒙面指数和mantessa进行OR(加入)。所以这应该适用于所有情况。
但是这是一个失败的情况: x = 0x7fc00000(2143289344)
答案 0 :(得分:1)
我问道:
当代码使用整数时,为什么要询问标题中的“浮点数”?您是否尝试使用
float
调用该函数并将其视为一个位数组,或多或少?如果是这样的话,那你就隐藏起来了!如果使用范围内的原型调用函数,C编译器会将float
转换为unsigned int
。如果你没有在范围内用原型调用它,C编译器会在调用函数之前将float
转换为double
。
答案是:
这是一个32位IEEE 754单精度数。所以我只是翻转最重要的位(符号位)。
要翻转32位(无符号整数)数量的最高位,您可以简单地写:
x ^= 0x80000000;
但是,正如我所指出的那样,除非你对编译器说谎,否则你根本就没有通过32位float
。如果你有:
extern float negate_number(float x);
...
float f1 = 3.14159;
float f2 = negate_number(f1);
...
unsigned negate_number(unsigned x)
{
return x ^ 0x80000000;
}
然而,你正在玩你的编译器。编译器讨厌被骗,并经常找到一种方法来获得自己的回报。 不要这样做!
要以最少的问题(但不是“没有问题”)或多或少地达到你想要的效果,你可能需要:
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
。
所有这些假设float
和unsigned
的位布局使得float
的符号位是unsigned
的最高位。< / p>