C#二进制移位自动旋转

时间:2013-12-09 10:23:32

标签: c# rotation bit-manipulation

我搜索了在C#中进行二进制旋转移位的方法,并得到了很好的答案,例如https://stackoverflow.com/a/812039/204693https://stackoverflow.com/a/35172/204693

我想为这个场景创建一个测试用例,其中非旋转移位可以作为负面测试,但后来我偶然发现了这个事实:

public static void Main()
{
    Debug.WriteLine("1<<31 = " + Convert.ToString(1 << 31, 2).PadLeft(32, '0'));
    Debug.WriteLine("1<<32 = " + Convert.ToString(1 << 32, 2).PadLeft(32, '0'));
}

提供以下输出:

1<<31 = 10000000000000000000000000000000
1<<32 = 00000000000000000000000000000001

现在,这些看起来很奇怪,因为有许多答案提供了二进制移位和旋转的方法,如二进制OR等技巧。但似乎.NET的默认行为是旋转。 / p>

在.NET的新版本中是否更改了此行为?我在Visual Studio 2010中尝试过这个到.NET 2.0,它总是显示上述行为。

为什么人们为旋转位创建了“聪明”的解决方案,如果这是默认行为?我在这里错过了什么吗?

2 个答案:

答案 0 :(得分:7)

它不会“旋转”;简单地说 - 只考虑操作数的一些位。基本上,1 << 32 相同 1 << 0

来自MSDN

  

如果第一个操作数是int或uint(32位数),则移位计数由第二个操作数的低位5位给出。也就是说,实际的移位计数是0到31位。

     

如果第一个操作数是long或ulong(64位数),则移位计数由第二个操作数的低位6位给出。也就是说,实际的移位计数是0到63位。

答案 1 :(得分:4)

如果在一次操作中没有完成比特移位,它如何不旋转它的例子:

var a = 1 << 16;
a.ToString("X8").Dump();

a = a << 8;
a.ToString("X8").Dump();

a = a << 8;
a.ToString("X8").Dump();

最后一次转储将显示a现在实际上为零。

换句话说,如果你在一次操作中完成所有的位移,你就会很好,花花公子,并且你会得到旋转行为(毕竟,它是操作数上的一个简单的模32)。但是,只要你比单次调用位移更频繁,就会丢失部分数字,直到你得到零。

此外,如果您使用的不仅仅是一位,那么您可以更快地到达目的地:

var a = 0xA1A2A3A4;
a.ToString("X8").Dump(); // "A1A2A3A4"

a = a << 8;
a.ToString("X8").Dump(); // "A2A3A400"!

a = a << 8;
a.ToString("X8").Dump(); // "A3A40000"

a = a << 8;
a.ToString("X8").Dump(); // "A4000000"