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

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

好的,所以我知道通常左移和右移仅针对值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/

相关文章:

java - 记录日志时,为该类动态创建日志文件,并仅在 log4j 中登录到该文件

java - Spring启动无法找到org.springframework :springloaded:jar:2. 1.6.RELEASE

c++ - const char* 到 int 转换?

c++ - 如何通过c中的指针传递二维数组

C typedef 中令人困惑的语法

java - com.fasterxml.jackson.databind.JsonMappingException : Direct self-reference leading to cycle (through reference chain)

具有与 MySQL utf8_general_ci 归类相似特性的 Java Collat​​or

c++ - std::max 与 lambda 和 auto

c++ - 如何使用 wxWidgets 和 C++ 绘制单色图像,然后将其 "dump"转换为 vector ?

c - 如何使用 fork() 来守护独立于其父进程的子进程?