Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# binary shift rotates automatically

I searched for methods to do a binary rotating shift in C#, and came across good answers, like https://stackoverflow.com/a/812039/204693 or https://stackoverflow.com/a/35172/204693

I wanted to create a testcase for this scenario, where a non-rotating shift would serve as a negative-test, but then I stumbled upon the fact that this:

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'));
}

Provides the following output:

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

Now, this seeems strange to me, as there are many answers out there that provide a method to binary shift and rotate with tricks like binary OR etc. But, it seems that the default behaviour of .NET is to rotate.

Has this behaviour changed in a new verison of .NET? I have tried this in Visual Studio 2010 down to .NET 2.0, and it always shows the above behaviour.

Why have people created "clever" solutions to rotating bits, if this is default behaviour? Am I missing something here?

like image 629
F.P Avatar asked Dec 09 '13 10:12

F.P


2 Answers

It doesn't "rotate" as such; simply - only some of the bits of the operand are considered. Basically, 1 << 32 is identical to 1 << 0.

From MSDN

If the first operand is an int or uint (32-bit quantity), the shift count is given by the low-order five bits of the second operand. That is, the actual shift count is 0 to 31 bits.

If the first operand is a long or ulong (64-bit quantity), the shift count is given by the low-order six bits of the second operand. That is, the actual shift count is 0 to 63 bits.

like image 165
Marc Gravell Avatar answered Nov 09 '22 03:11

Marc Gravell


An example of how it doesn't rotate the bitshifting if it's not done in one operation:

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

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

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

The last dump will show that a is now in fact zero.

In other words, if you do all the bitshifting in one operation, you're fine and dandy, and you get rotating behaviour (after all, it's a simple modulo 32 on the operand). However, as long as you call the bitshifts more often than just once, you lose parts of the number until you get zero.

Also, you get there faster if you use more than just one bit:

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"
like image 39
Luaan Avatar answered Nov 09 '22 02:11

Luaan