【发布时间】:2020-04-26 23:40:23
【问题描述】:
作为练习,我必须编写以下函数:
将 x 乘以 2,如果溢出则饱和到 Tmin / Tmax,仅使用逐位和位移操作。
现在这是我的代码:
// xor MSB and 2nd MSB. if diferent, we have an overflow and SHOULD get 0xFFFFFFFF. otherwise we get 0.
int overflowmask = ((x & 0x80000000) ^ ((x & 0x40000000)<<1)) >>31;
// ^ this arithmetic bit shift seems to be wrong
// this gets you Tmin if x < 0 or Tmax if x >= 0
int overflowreplace = ((x>>31)^0x7FFFFFFF);
// if overflow, return x*2, otherwise overflowreplace
return ((x<<1) & ~overflowmask)|(overflowreplace & overflowmask);
现在当overflowmask 应该是0xFFFFFFFF 时,它改为1,这意味着算术位移>>31 移位了0s 而不是1s(MSB 异或到1,然后移位到底部)。
x 有符号且 MSB 为 1,因此根据 C99,算术右移应填充 1。我错过了什么?
编辑:我只是猜想这段代码不正确。要检测溢出,第二个 MSB 为 1 就足够了。
但是,我仍然想知道为什么移位填充为 0。
编辑:
示例:x = 0xA0000000
x & 0x80000000 = 0x80000000
x & 0x40000000 = 0
XOR => 0x80000000
>>31 => 0x00000001
编辑:
解决方案:
int msb = x & 0x80000000;
int msb2 = (x & 0x40000000) <<1;
int overflowmask = (msb2 | (msb^msb2)) >>31;
int overflowreplace = (x >>31) ^ 0x7FFFFFFF;
return ((x<<1) & ~overflowmask) | (overflowreplace & overflowmask);
【问题讨论】:
-
使用 signed 值的按位运算总是会有问题。
-
所以我只需要想出一个不同的解决方案,因为 c 不像它所说的那样工作?
-
您能否告诉我们
x的一些值,它不能按您的预期工作?您是否尝试过将您拥有的复杂表达式划分为更小且更易于调试的表达式,以查看每个小的子表达式给出您期望的值? -
发生了什么是
x & 0x80000000中的0x80000000变成了一个无符号 整数,使得整个表达式无符号。 或0x80000000是long或long long值,这意味着它不是负数。因此,您正在移动一个无符号或其他非负数,这意味着它用零而不是一填充。我正在尝试查找有关此行为的参考或引用以获得答案。 -
它可以是
unsigned int或 64 位有符号整数(long或long long,取决于平台和编译器)。
标签: c bit-manipulation bit-shift