好的,所以我知道通常左移和右移仅针对值0..31
定义良好。我正在考虑如何最好地将其扩展到包括 32,这简化了一些算法。我想出了:
int32 << n & (n-32) >> 5
这似乎有效。问题是,它是否能保证在任何架构(C、C++、Java)上工作,并且可以更有效地完成?
最佳答案
在 Java 中,如果这些变量的类型为 int
,则保证可以工作。 ,自 >>
在Java中进行算术右移并且移位超过31也有定义的行为。但要注意运算符优先级
int lshift(int x, int n)
{
return (x << n) & ((n-32) >> 5);
}
这适用于轮类数最多 32。但可以修改它以包含任何移位计数大于 31 的 int 值 return 0
return (x << n) & ((n-32) >> 31);
但是在 C 和 C++ 中 int
的大小>>
的类型和行为运算符是 implementation defined 。大多数(如果不是全部)现代实现将其实现为有符号类型的算术移位。此外,移动超过可变宽度的行为是 undefined 。更糟糕的是,有符号溢出会调用 UB,因此即使左移 31 也是 UB ( until C++14 )。因此,要获得明确定义的输出,您需要
- 使用无符号的固定宽度类型,例如
uint32_t
(所以x << 31
不是 UB) - 使用为
>>
发出算术右移指令的编译器并使用n
的有符号类型,或者自己实现算术移位 - 对
int32_t
屏蔽移位量,将其限制为 5 位
结果是
uint32_t lshift(uint32_t x, int32_t n)
{
return (x << (n & 0x1F)) & ((n-32) >> 31);
}
如果架构支持conditional instructions像x86或ARM那么下面的方式可能会更快
return n < 32 ? x << n : 0;
在 64 位平台上,您可以通过先移入 64 位类型然后再进行掩码来使此操作变得更加简单。一些 32 位平台(例如 ARM)确实支持 32 位移位,因此这种方法也很有效
return ((uint64_t)x << (n & 0x3F)) & 0xFFFFFFFFU;
可以看到输出程序集here 。我不知道如何进一步改进
关于java - 如何将 32 位 int 移位 32(再次),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35114538/