When to use Shift operators << >> in C#?

20,567

Solution 1

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.

Solution 2

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.

Solution 3

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
}

Solution 4

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.

Share:
20,567
Junior Mayhé
Author by

Junior Mayhé

Brazilian Software Engineer graduated in Information Systems. Fluent in English and Spanish. ITIL and SCRUM certificated professional. Solid experience throughout the life cycle of software development. Working for over 15 years designing, building and deploying solutions for areas like Human Resources, Finance, Publishing, Telecommunications, Entertainment, Healthcare, Logistics and Energy. International experience interacting with professionals from several countries like Italy, Belgium, Portugal, Holland, USA, Colombia, Spain and Mexico. 10 years of experience in systems analysis, requirements gathering, object-oriented analysis, data modeling, technical specification. 15 years in systems development, maintenance, testing for national and international companies. 4 years interacting with professionals from different countries, of which 2 years playing technical project leadership role abroad, delegating, and following up tasks. 3 years negotiating with infrastructure and service providers. 2 years defining the IT tools and infrastructure to be implemented and processes to be improved, covering software, hardware, communications needs, to meet the needs of the organization. 2 years organizing and supervising the acquisition and update of computer systems, whether hardware or software (licenses, servers, contracts). Specialties: Systems Analysis, Requirements Analysis, Functional Analysis, Software Development, Project Management, SCRUM Agile methodology, Waterfall methodology, ITIL, Software Testing, Continuous Integration, C# programming language, ASP.NET MVC, Entity Framework, Windows Forms, WPF, WCF, .NET Core, ASP.NET Web API, JavaScript, Angular 6, TypeScript, JQuery, HTML5, CSS3, XML, XSD, XAML, SQL Server, PHP, MySQL, MongoDB, BPM, UML, GIT, Prototyping, Database Modeling and Administration Personal Site | Linkedin profile

Updated on June 05, 2020

Comments

  • Junior Mayhé
    Junior Mayhé almost 4 years

    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#?

  • Ben Voigt
    Ben Voigt over 14 years
    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.
  • cdonner
    cdonner over 14 years
    "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.
  • ClickRick
    ClickRick almost 10 years
    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)