53

I was doing some basic audio programming in C# using the NAudio package and I came across the following expression and I have no idea what it means, as i've never seen the << operator being used before. So what does << mean?

Please give a quick explaination of this expression.

short sample = (short)((buffer[index + 1] << 8) | buffer[index + 0]);
Jon Seigel
  • 12,251
  • 8
  • 58
  • 92
Kurru
  • 14,180
  • 18
  • 64
  • 84
  • 5
    I'm not downvoting, but it strikes me as an RTFD question. – Aaronaught Jan 05 '10 at 16:49
  • I wonder why before asking `What does the operator “<<” mean in C#?` you elementary don't google this question? – serhio Jan 05 '10 at 16:52
  • 9
    serhio: have fun googling for "<<" and "C#". Google doesn't play well with non-alphabetic characters. – Joey Jan 05 '10 at 16:53
  • 6
    @Johannes: But you *can* type it directly into the index of the VS documentation. – Aaronaught Jan 05 '10 at 16:58
  • @Johannes: If you know what you search, you will quickly find it. I've searched `"<< operator C#"` – serhio Jan 05 '10 at 16:59
  • serhio: Still, the result set is exactly the same as with "operator C#". Google just strips out the actually important part there :-) – Joey Jan 05 '10 at 17:01
  • 6
    As long as its not already been asked on SO, it's good to have it on here – Charlie Jan 05 '10 at 17:04
  • I did a google search, but evidently not a very successful one! But thank you everyone for your help. First time coming across the left shift operator in anything since my assembly module. – Kurru Jan 05 '10 at 17:10
  • 1
    @Johannes: yeah, you are right. However, if you arrive at the C# operators page you can easily find the desired one. :) – serhio Jan 05 '10 at 17:10
  • Maybe they asked on here rather than Googling because that would have led to the Microsoft documentation, which is rubbish. The answers given on SO are always much better explained with real-world examples. – ataraxia Feb 26 '21 at 10:23

10 Answers10

74

Definition

The left-shift operator (<<) shifts its first operand left by the number of bits specified by its second operand. The type of the second operand must be an int. << Operator (MSDN C# Reference) alt text

For binary numbers it is a bitwise operation that shifts all of the bits of its operand; every bit in the operand is simply moved a given number of bit positions, and the vacant bit-positions are filled in.

Usage

Arithmetic shifts can be useful as efficient ways of performing multiplication or division of signed integers by powers of two. Shifting left by n bits on a signed or unsigned binary number has the effect of multiplying it by 2n. Shifting right by n bits on a two's complement signed binary number has the effect of dividing it by 2n, but it always rounds down (towards negative infinity). This is different from the way rounding is usually done in signed integer division (which rounds towards 0). This discrepancy has led to bugs in more than one compiler.

An other usage is work with color bits. Charles Petzold Foundations article "Bitmaps And Pixel Bits" shows an example of << when working with colors:

ushort pixel = (ushort)(green << 5 | blue);
Community
  • 1
  • 1
serhio
  • 28,010
  • 62
  • 221
  • 374
  • 3
    I've updated this answer because shifting multiplies/divides by 2^n, not 2n – John Rasch Jan 05 '10 at 19:28
  • Note that while there is only one type of left shift there are two types of right shift. "arithmetic shift" sign extends while "logical shift" zero extends. C# does the right thing depending on the type of the operand. C on the other hand does the right thing for positive numbers but leaves the handling of signed types containing negative numbers as "implementation defined". – plugwash Jan 12 '16 at 14:20
9

Shift left (and the counterpart, Shift right) moves the bits in the given direction.

Shift left is more or less times 2, but faster

Shift right is more or less divided by 2, but faster

Benjamin Podszun
  • 9,679
  • 3
  • 34
  • 45
  • 9
    You can safely leave out the comparison to multiplying or dividing by two. This just gets us another bunch of programmers who think they can out-smart the compiler by writing `x << 1` instead of `x * 2`. No −1 from me, but close. – Joey Jan 05 '10 at 16:46
  • 2
    But it is probably the reason why it was used in his audio code. So - my hope is to help him to understand not only what it does, but also the probable intention. – Benjamin Podszun Jan 05 '10 at 16:48
  • 3
    If the intention was arithmetic, i. e. × 2, then I think it's a very bad idea to use bit shifts. If the intention was bitwise, i. e. “move those bits around a bit”, then of course it's the right idiom. Remember that it has to make sense to someone reading the code. The compiler is almost always better at figuring out how to write it properly that it performs as fast as possible. (And seeing the code it very obviously is a *bitwise* context, not an arithmetic one—it combines two bytes into one word). – Joey Jan 05 '10 at 16:50
  • 4
    @Benjamin: The "but faster" claims are misleading. I'm pretty sure that the compiler and/or JITter recognises integer `*2` and `/2` calculations and uses a shift instruction anyway where possible, so in C# there is no performance benefit. – LukeH Jan 05 '10 at 16:53
  • 1
    +1 to Luke. Something like `x * 2` might even be rewritten to `x + x` in some cases :-) – Joey Jan 05 '10 at 16:56
  • @Johannes: I don't know more about the context, but audio/video and limited/embedded devices (we can argue if C# is relevant there..) might call for integer math @Luke: Good point I see both of your points. Suggestions how I can soften it up? – Benjamin Podszun Jan 05 '10 at 16:57
7

It's a left bit shift operation, a VERY common programming idiom: http://en.wikipedia.org/wiki/Arithmetic_shift

mletterle
  • 3,968
  • 1
  • 24
  • 24
  • 1
    It is if you're playing the part of a bit flipper :) Alot of people doing C# aren't "plumbers" though so they don't see all that niftyness. – mletterle Jan 05 '10 at 16:47
  • 1
    @Kragen, IMHO, is not common not only in C# but also in other programming languages. Evidently, if you perform complex binary or logical bit operations this will be a common for you... – serhio Jan 05 '10 at 16:55
  • @serhio - Is that an intentional double negative? Makes it difficult to get your point. Are you agreeing with Kragen? Seems like you are but then you last sentence suggests you arn't. – gingerbreadboy Jan 05 '10 at 17:01
  • @runrunraygun: Yes, I not only agree with Kragen, but also extend his affirmation to the programming world in general. In the past, when working more with binary numbers that should be a common (maybe even VERY common) operator. Not now, in the OOP era... if you get the point.. – serhio Jan 05 '10 at 17:18
4

It's called left-shift operator.

Follow this link for more detailed information.

missingfaktor
  • 90,905
  • 62
  • 285
  • 365
3

The bitwise operator has already been explained quite a few times already. Let's say that buffer[0] contains 1, buffer[1] contains 2 and index is 0 and replace these values:

short sample = (short)((buffer[1] << 8) | buffer[0]);
short sample = (short)((1 << 8) | 2);

Now, a semi-graphical representation. This is the numeral 1 in a binary representation:

0000 0001

Shifting eight positions to the left would make this number to "overflow" from a single byte. However, the compiler is smart enough to give us more room.

0000 0001 0000 0000

Now, the right part: the number 2 looks like this in binary:

0000 0010

And the "|" operator (bitwise OR) makes just put the two values together and comparing bit per bit.

  0000 0001 0000 0000
| 0000 0000 0000 0010
= 0000 0001 0000 0010

And the final value is stored in your "sample" variable (in this case, 258.) The reverse operation is similar:

buffer[0] = sample & 255;
buffer[1] = (sample & (255 << 8)) >> 8;
Leonardo Herrera
  • 8,388
  • 5
  • 36
  • 66
  • 1
    I got confused a bit reading your setup. Shouldn't you say buffer[0] contains 2 and buffer[1] contains 1? Or swap around the buffer[0] and buffer[1] so they match what you are saying if you maintain buffer[0] = 1 and buffer[1] = 2. short sample = (short)((buffer[0] << 8) | buffer[1]); short sample = (short)((1 << 8) | 2); – Patratacus Feb 21 '22 at 16:27
1

Left shift Here is some msdn to help you : http://msdn.microsoft.com/en-us/library/ayt2kcfb(VS.80).aspx

JonH
  • 32,732
  • 12
  • 87
  • 145
1

As a few people have pointed out already it is a shift operation.

However It is worth noting that depending on whether the operand is a signed integral type or a unsigned integral type it will apply either an arithmetic or logical shift.

See the bottom of this page on msdn.

Nifle
  • 11,745
  • 10
  • 75
  • 100
gingerbreadboy
  • 7,386
  • 5
  • 36
  • 62
1

The "<<" is a shift left operator. x << y shifts bit pattern x y position left.

For example, if x was 0001 0101 and y was 1 then the result would be 0010 1010. It's like someone's pushed each bit left one.

wdh
  • 1,612
  • 12
  • 16
1

As others have said the << operator moves the bits of a number left. The normal reason why someone would do this in an Audio application is to combine two 8bit mono-samples (one for left and right) into a 16 bit sterio sample.

So in the sample code it looks like Buffer contains sterio encoded with left and right in alternate samples. By shifting the first left 8 and oring the second the author is combining them to form a 16bit sterio sample with the High 8bits being one channel and the low 8bits being the other.

If in your example the buffer contained:

1001 0100 (Right)
1001 0011 (Left)

The result you would get in sample is:

(Left)    (Right)
1001 0011 1001 0100
Martin Brown
  • 24,692
  • 14
  • 77
  • 122
-1

I stumbled upon << and >> during a CodeWars-kata, and to add to previous answers about bit shifting, when using Godbolt's Compiler Explorer this operation apparently compiles to the same code as n * 2.

In C#:

class Program
{
    static int Multiply(int num) => num * 2;
    static int BitShift(int num) => num << 1;
}

Compiled in .NET 6:

Program:.ctor():this:
       ret      

Program:BitShift(int):int:
       lea      eax, [rdi+rdi]
       ret      

Program:Multiply(int):int:
       lea      eax, [rdi+rdi]
       ret       

Reference:

https://godbolt.org/z/fno7vEWfT

https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/bitwise-and-shift-operators

Robhimself
  • 21
  • 5