30

I was studying shift operators in C#, trying to find out when to use them in my code.

I found an answer but for Java, you could:

a) Make faster integer multiplication and division operations:

*4839534 * 4* can be done like this: 4839534 << 2

or

543894 / 2 can be done like this: 543894 >> 1

Shift operations much more faster than multiplication for most of processors.

b) Reassembling byte streams to int values

c) For accelerating operations with graphics since Red, Green and Blue colors coded by separate bytes.

d) Packing small numbers into one single long...


For b, c and d I can't imagine here a real sample.

Does anyone know if we can accomplish all these items in C#? Is there more practical use for shift operators in C#?

Jon Seigel
  • 12,251
  • 8
  • 58
  • 92
Junior Mayhé
  • 16,144
  • 26
  • 115
  • 161
  • 11
    "Make faster integer multiplication and division operations." Don't do this. Modern compilers will do it for you. It just makes your code harder to read. – jason Dec 19 '09 at 17:45
  • 11
    That shifting was faster than multiplication was true in *some* badly optimized C compilers back in the 1980's. It's an urban legend that it still makes a difference. – Eric Lippert Dec 19 '09 at 18:20

4 Answers4

38

There is no need to use them for optimisation purposes because the compiler will take care of this for you.

Only use them when shifting bits is the real intent of your code (as in the remaining examples in your question). The rest of the time just use multiply and divide so readers of your code can understand it at a glance.

GraemeF
  • 11,327
  • 5
  • 52
  • 76
17

Unless there is a very compelling reason, my opinion is that using clever tricks like that typically just make for more confusing code with little added value. The compiler writers are a smart bunch of developers and know a lot more of those tricks than the average programmer does. For example, dividing an integer by a power of 2 is faster with the shift operator than a division, but it probably isn't necessary since the compiler will do that for you. You can see this by looking at the assembly that both the Microsoft C/C++ compiler and gcc perform these optimizations.

Mark Wilkins
  • 40,729
  • 5
  • 57
  • 110
15

I will share an interesting use I've stumbled across in the past. This example is shamelessly copied from a supplemental answer to the question, "What does the [Flags] Enum Attribute mean in C#?"

[Flags]
public enum MyEnum
{
    None   = 0,
    First  = 1 << 0,
    Second = 1 << 1,
    Third  = 1 << 2,
    Fourth = 1 << 3
}

This can be easier to expand upon than writing literal 1, 2, 4, 8, ... values, especially once you get past 17 flags.

The tradeoff is, if you need more than 31 flags (1 << 30), you also need to be careful to specify your enum as something with a higher upper bound than a signed integer (by declaring it as public enum MyEnum : ulong, for example, which will give you up to 64 flags). This is because...

1 << 29 == 536870912
1 << 30 == 1073741824
1 << 31 == -2147483648
1 << 32 == 1
1 << 33 == 2

By contrast, if you set an enum value directly to 2147483648, the compiler will throw an error.

As pointed out by ClickRick, even if your enum derives from ulong, your bit shift operation has to be performed against a ulong or your enum values will still be broken.

[Flags]
public enum MyEnum : ulong
{
    None   = 0,
    First  = 1 << 0,
    Second = 1 << 1,
    Third  = 1 << 2,
    Fourth = 1 << 3,

    // Compiler error:
    // Constant value '-2147483648' cannot be converted to a 'ulong'
    // (Note this wouldn't be thrown if MyEnum derived from long)
    ThirtySecond = 1 << 31,

    // so what you would have to do instead is...
    ThirtySecond = 1UL << 31,
    ThirtyThird  = 1UL << 32,
    ThirtyFourth = 1UL << 33
}
Community
  • 1
  • 1
aaaantoine
  • 900
  • 8
  • 19
  • If exceeding `int.MaxValue`, then you need to specify the values explicitly as longs, or as something which will evaluate to a long, such as `E32 = 1L << 32`, even if you've declared the enum as deriving from long. *(or ulong, as the case may be)* – ClickRick Jun 03 '14 at 21:26
6

Check out these Wikipedia articles about the binary number system and the arithmetic shift. I think they will answer your questions.

The shift operators are rarely encountered in business applications today. They will appear frequently in low-level code that interacts with hardware or manipulates packed data. They were more common back in the days of 64k memory segments.

cdonner
  • 37,019
  • 22
  • 105
  • 153
  • Packed data is still pretty common, but C# programmers should use BitConverter (not BinaryReader) or BitVector for development. Only if that code is verified as a performance problem would you go back and rewrite with explicit bit manipulation operators. – Ben Voigt Dec 19 '09 at 18:03
  • "pretty common" is a relative term. The last time I worked with packed data was in 1992, I think, when I had to fit the coordinates of 8000 stars into a single data segment. – cdonner Dec 19 '09 at 18:39