首页 > 解决方案 > MSB 为 1 时算术右移 0s

问题描述

作为练习,我必须编写以下函数:
将 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位移在 0 中而不是 1 中移动(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);

标签: cbit-manipulationbit-shift

解决方案


>>即使在二进制补码机器上,负操作数上的右移 ( ) 行为也是由实现定义的。

一种更安全的方法是使用无符号类型并在 MSB 中显式地 OR-。

当您使用它时,您可能还想使用固定宽度类型(例如uint32_t),而不是在不符合您期望的平台上失败。


推荐阅读