Get Shifty (Bitwise Operations)

Image result for get schwifty

As I fired up my pc today I actually looked at those post-it notes that have been sat on my desktop. And one of those little tasks was “Stuff I need to brush up on – C# Bit Shifting”. Have you ever used a bitwise operation? I have maybe once. Have you needed to do a bitshift in real life? On the other hand, have you ever been to a coding job and have to do one of those coding tests and it had bit shifting is on it? Yeah ok. Essentially, it is one of those things that in 2017 (or nearly 2018) you are unlikely to have used bit shifting, etc day to day, but it is one of those things that it is kind of useful to know. I was super rusty on it because I mainly do gameplay programming, graphics and SDK integration inside of Unity day to day. The closest I come is using Flags.

Anyway, to the plot!

So what are Bitwise operations?

Well they are operators like +, -, * &&, etc, etc that operate on ints and uints at a binary level. This means that they operate upon the actual digits of a binary integer.

To put it another way. See these binary numbers I stole from google images:

Image result for binary numbers

The bitwise operators operate on the binary numbers. Get it? Well, here is the binary table, to remind you of how binary number are represented:

128 64 32 16 8 4 2 1
1 1 0 1 0

Basically, the operators change where the ones and zeroes go in a binary number.

So let’s look at some of these operators! We are looking at operators in C#, because C# is a beautiful language.

Bitwise AND (&)

The & operator compares each binary digit of two integers and returns a new integer with a 1 wherever both numbers had a 1 and 0 anywhere else. Let’s look at 2 numbers:

128 64 32 16 8 4 2 1
 0  0  1 0 0 1 0 0

The above number is 36.

128 64 32 16 8 4 2 1
 0  0  0 1 0 1 1 0

And the above number here is 22.

If we use the & operator on both, we take wherever both numbers had a 1. This produces 4.

128 64 32 16 8 4 2 1
 0  0  0 0 0 1 0 0

Basically, the operators change where the ones and zeroes go in a binary number.

Sure OK. But why is it actually useful? Well we can look in the context of flags.

A flag is a special enum that can hold multiple values at a time.

[Flags]
public enum AttackType
{
    NoEffect = 0
    Melee = 1,
    Fire = 2,
    Ice = 4,
    Wind = 5,
...
}

Imagine we have a JRPG. In a JRPG abilities have elements and abilities. Abilities could have multiple elements. We could use a flag for that. Say we want to check if an ability has Fire and Wind in it. We can use the bitwise & operator.

int mask = AttackType.Fire | AttackType.Wind;
bool isFireAndWind = (attackType & mask) == mask

The above bool will return true.

Bitwise OR (|)

The | operator compares each binary digit across to integers and gives back 1 if either of them are 1. Unlike AND where both have to be 1, 1 could be in well one or the other.

128 64 32 16 8 4 2 1
 0  0  1 0 0 1 0 0

The above number is 36.

128 64 32 16 8 4 2 1
 0  0  0 1 0 1 1 0

And the above number here is 22.

You know, like last time. If we apply OR.

128 64 32 16 8 4 2 1
 0  0  1 1 0 1 1 0

The above number is 54.

Makes sense?

Cool. Let’s have a look at our JRPG example again:

_ability.AttackType = AttackType.Fire | AttackType.Wind;

The above code is setting the ability’s attack type to Fire and Wind. The game can then check this later when doing the battle calcs.

Bitwise NOT (~)

The bitwise ~ operator is different than the previous ones we have looked at. Where as the & has been similar to && and the | has been similar to ||, the ~ operator is similar to the ! operator. You know how the ! operator can flip a boolean from true to false. The ~ operator reverses a binary value.

128 64 32 16 8 4 2 1
 0  0  1 0 0 1 0 0

The above number is 36.

The same as last time. If we apply the operator to it we get:

128 64 32 16 8 4 2 1
 1  1  0 1 1 0 1 0

OK cool. I mean to me this is not the useful part of the NOT operator for gameplay programming anyway.

If we look at our JRPG example with our flags. You can use the NOT operator to unset a flag.

_ability.AttackType = AttackType.Fire | AttackType.Wind;
_ability.AttackType &= ~AttackType.Wind;

The above will remove the Wind element from the ability.

Bitwise XOR (^)

The ^ operator, like the previous operators, compares the binary digits of these numbers. If only one of the two comparing integers in the binary is a 1, it inserts a 1 into the result. Otherwise a 0 is inserted.

128 64 32 16 8 4 2 1
 0  0  1 0 0 1 0 0

The above number is 36.

128 64 32 16 8 4 2 1
 0  0  0 1 0 1 1 0

And the above number here is 22.

You know like all the previous times.

128 64 32 16 8 4 2 1
 0  0  1 1 0 0 1 0

And the result is 50.

Cool. So in regards to our example, the EXCLUSIVE OR is true only if the other is true, but not both. We can use it to toggle a value inside a flag.

_ability.AttackType = AttackType.Fire | AttackType.Wind;
_ability.AttackType ^= AttackType.Wind;

The above code “toggles” Wind.

Bitwise Shifting (<< / >>)

Bitwise shift operators work a little differently than before. Instead of comparing 2 integers, these operators shift an integer.

128 64 32 16 8 4 2 1
 0  0  1 0 0 0 1 1

The above number is 37. If we 37 << 3 we slide all the digits left by 3

128 64 32 16 8 4 2 1
 0  0  0 0 1 1 0 0

And the above number here is 12. You can also right shift the integer >> by any number that does a similar thing.

This is a harder one to find a decent example, or at least I cannot think of a time I have actively had to use it. If you look at the maths of bitshifting though, you can use it to do calculations. Shifting the bits of an integer number left by one place is the equivalent to multiplying the number by 2, whereas shifting it right is equivalent to dividing it by 2. I guess an example could be hardware that was used back in the day. This hardware did not have floating point support and thus in order to do any arithmetic, you had to do bitshifting. Wierd huh?

Again, I have never needed this in my day to day, but it is one of those things I have seen in programming tests. I have theorised why this stuff is probably still on tests in the past and the whole “programming test” is a post for another day.

Regardless, I hope this post will be helpful in some way when understanding bitwise operations, flags and bitshifting.

Share

5 thoughts on “Get Shifty (Bitwise Operations)

  1. A couple of notes:
    Usually we write enums intended for bitwise operations like so:
    public enum AttackType
    {
    Melee = 0,
    Fire = 1 << 0,
    Ice = 1 << 1,
    Wind = 1 << 2
    }
    So 0, 1, 2, 4, etc. Defining it with a shift like above makes it easy to avoid mistakes. I would also probably use 0 as NoEffect value instead of melee. Unless you are certain melee would never have any effect.
    You have set Wind to be 3, this means that your Wind always includes fire (the bit for fire is always active on Wind). You probably don't want to do that, so you have to set it to 4 instead. That way each effect type will have its own unique bit.

    Also on the bitwise shifting section you probably forgot to set the first bit for 37 to 1.

    • Added note:
      To check if it is fire and wind you would have to do:
      (attackType & (AttackType.Fire | AttackType.Wind)) != 0

      So you build what you want to check against (fire | wind) and then check it against attackType which is probably an int.

        • You should still avoid using 3 in your enum, since 3 is 1 + 2, so with the new changes it means that Melee + Fire = Ice (or AttackType.Melee | AttackType.Fire == AttackType.Ice in actual code). Use unique bits for each type.

          Also realised I made a mistake as well, (attackType & (AttackType.Fire | AttackType.Wind)) != 0 checks if the attack type is Fire or Wind, not if it is both. What you actually need to do to check if it is both at the same time is:
          int mask = AttackType.Fire | AttackType.Wind;
          bool isFireAndWind = (attackType & mask) == mask

          • What I am getting is enums and flags are kind of crap for this and what i have done in my actual project is just kept a list/hashset 😛

Leave a Reply

Your email address will not be published. Required fields are marked *

Verify that you are not a robot! (If you are unlucky) *