如何将32位int移位32(再次)

时间:2016-01-31 13:47:55

标签: java c++ c bit-manipulation bit-shift

好的,所以我知道通常只对值0..31定义左右移位。我在想如何最好地扩展它包括32,这简化了一些算法。我提出了:

 int32 << n & (n-32) >> 5

这似乎有效。问题是,它是否可以保证适用于任何架构(C,C ++,Java),是否可以更有效地完成?

1 个答案:

答案 0 :(得分:3)

在Java中,如果这些变量的类型为int,则保证可以正常工作,因为Java中的>>执行算术右移并且移位超过31也具有已定义的行为。但要注意运算符优先级

int lshift(int x, int n)
{
    return (x << n) & ((n-32) >> 5);
}

这适用于班次计数高达32 。但它可以修改为包含任何移位数大于31的int值返回0

return (x << n) & ((n-32) >> 31);

但是在C和C ++中,int类型的大小和>>运算符的行为是implementation defined。大多数(如果不是全部)现代实现将其实现为签名类型的算术移位。此外,移动超过可变​​宽度的行为是undefined。更糟糕的是,签名溢出调用UB,因此即使左移31也是UB(until C++14)。因此,要获得明确定义的输出,您需要

  • 使用类似uint32_t的无符号固定宽度类型(因此x << 31不是&lt; uB)
  • 使用为>>发出算术右移指令的编译器,并为n使用带符号的类型,或自己实现算术移位
  • 屏蔽移位量,将int32_t
  • 限制为5位

结果将是

uint32_t lshift(uint32_t x, int32_t n)
{
    return (x << (n & 0x1F)) & ((n-32) >> 31);
}

如果架构支持{x}或ARM等conditional instructions,则以下方式可能更快

return n < 32 ? x << n : 0;

您可以看到输出程序集here。我不知道如何进一步改进