好的,所以我知道通常只对值0..31
定义左右移位。我在想如何最好地扩展它包括32,这简化了一些算法。我提出了:
int32 << n & (n-32) >> 5
这似乎有效。问题是,它是否可以保证适用于任何架构(C,C ++,Java),是否可以更有效地完成?
答案 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
结果将是
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。我不知道如何进一步改进