【问题标题】:Is there a way to perform a circular bit shift in C#?有没有办法在 C# 中执行循环位移?
【发布时间】:2008-08-29 19:54:43
【问题描述】:

我知道以下是正确的

int i = 17; //binary 10001
int j = i << 1; //decimal 34, binary 100010

但是,如果你移动得太远,位就会从末端掉下来。发生这种情况的地方取决于您正在使用的整数的大小。

有没有办法执行移位,以便位旋转到另一侧?我正在寻找单个操作,而不是 for 循环。

【问题讨论】:

  • 这种类型的操作应该在哪里使用?进行位旋转的目的是什么?我不需要知道,只是对不断扩展的知识感兴趣。基思
  • 一个很好的问题。我刚刚检查了生成的代码,C# 编译器没有生成使用 CPU 旋转指令的代码(不是说 x86 架构自 8086 以来就有它们......)。这是一种耻辱。 C 执行此优化。轮换对于加密和 dsp 任务也非常重要。

标签: c# bit-manipulation


【解决方案1】:

如果你知道字体的大小,你可以这样做:

uint i = 17;
uint j = i << 1 | i >> 31;

... 执行 32 位值的循环移位。

作为对 b 位变量循环左移 n 位的概括:

/*some unsigned numeric type*/ input = 17;
var result = input  << n | input  >> (b - n);


@评论,看来C#确实以不同的方式对待有符号值的高位。我在这个here 上找到了一些信息。我还将示例更改为使用 uint。

【讨论】:

  • 由于我不懂C#,移位运算符是在做算术移位还是逻辑移位?如果是算术,那么这个算法不能用于 64 位有符号整数。
  • 所以也许'int'和'var'类型都应该以'unsigned'修饰符作为前缀,当然如果C#允许的话。
  • 好吧,无论如何,位旋转只对无符号整数有意义。
  • @LasseV.Karlsen:我不一定同意这一点。 GetHashCode 返回一个(有符号的)int,如果你想通过使用它的全部 32 位来均匀分布哈希码(这可以涉及位旋转),这个符号并不是真的问题 - 显然会妨碍钻头旋转。
  • 奇怪的是它甚至需要这么多代码,因为 rorrol 都是裸 x86 CPU 指令集的一部分。难道他们不能在 C# 中创建一个 &lt;&lt;&gt; 指令或其他东西吗?
【解决方案2】:

一年前,我必须为我的本科论文实施 MD4。这是我使用 UInt32 实现的循环位移。

private UInt32 RotateLeft(UInt32 x, Byte n)
{
      return UInt32((x << n) | (x >> (32 - n)));
}

【讨论】:

    【解决方案3】:

    自从 .NET Core 3.0 及更高版本有 BitOperations.RotateLeft()BitOperations.RotateRight() 所以你可以使用类似的东西

    BitOperations.RotateRight(12, 3);
    BitOperations.RotateLeft(34L, 5);
    

    在以前的版本中,您可以在 Microsoft.VisualStudio.Utilities 中使用 BitRotator.RotateLeft()BitRotator.RotateRight()

    【讨论】:

      【解决方案4】:

      作为如何做的参考,这两个函数非常适合旋转 1/2word 的位:

      static public uint ShiftRight(uint z_value, int z_shift)
      {
          return ((z_value >> z_shift) | (z_value << (16 - z_shift))) & 0x0000FFFF;
      }
      
      static public uint ShiftLeft(uint z_value, int z_shift)
      {
          return ((z_value << z_shift) | (z_value >> (16 - z_shift))) & 0x0000FFFF;
      }
      

      它很容易扩展到任何给定的大小。

      【讨论】:

        【解决方案5】:

        uint(32位)位旋转的扩展方法:

        public static uint ROR(this uint x, int nbitsShift)
            => (x >> nbitsShift) | (x << (32 - nbitsShift));
        
        public static uint ROL(this uint x, int nbitsShift)
            => (x << nbitsShift) | (x >> (32 - nbitsShift));
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2020-10-22
          • 2011-04-30
          • 2023-03-14
          • 2011-02-05
          • 1970-01-01
          • 1970-01-01
          • 2023-01-09
          相关资源
          最近更新 更多