In order to understand the bit manipulation operators, it is first necessary to understand how integers are represented in binary. We talked a little bit about this in section 2.4 -- Integers, and will expand upon it here.

Consider a normal decimal number, such as 5623. We intuitively understand that these digits mean (5 * 1000) + (6 * 100) + (2 * 10) + (3 * 1). Because there are 10 decimal numbers, the value of each digit increases by a factor of 10.

Binary numbers work the same way, except because there are only 2 binary digits (0 and 1), the value of each digit increases by a factor of 2. Just like commas are often used to make a large decimal number easy to read (e.g. 1,427,435), we often write binary numbers in groups of 4 bits to make them easier to read (e.g. 1101 0101).

As a reminder, in binary, we count from 0 to 15 like this:

Decimal Value | Binary Value |
---|---|

0 | 0 |

1 | 1 |

2 | 10 |

3 | 11 |

4 | 100 |

5 | 101 |

6 | 110 |

7 | 111 |

8 | 1000 |

9 | 1001 |

10 | 1010 |

11 | 1011 |

12 | 1100 |

13 | 1101 |

14 | 1110 |

15 | 1111 |

**Converting binary to decimal**

In the following examples, we assume that we’re dealing with unsigned integers.

Consider the 8 bit (1 byte) binary number 0101 1110. Binary 0101 1110 means (0 * 128) + (1 * 64) + (0 * 32) + (1 * 16) + (1 * 8) + (1 * 4) + (1 * 2) + (0 * 1). If we sum up all of these parts, we get the decimal number 64 + 16 + 8 + 4 + 2 = 94.

Here is the same process in table format. We multiply each binary digit by its digit value (determined by its position). Summing up all these values gives us the total.

Converting 0101 1110 to decimal:

Binary digit | 0 | 1 | 0 | 1 | 1 | 1 | 1 | 0 |

* Digit value | 128 | 64 | 32 | 16 | 8 | 4 | 2 | 1 |

= Total (94) | 0 | 64 | 0 | 16 | 8 | 4 | 2 | 0 |

Let’s convert 1001 0111 to decimal:

Binary digit | 1 | 0 | 0 | 1 | 0 | 1 | 1 | 1 |

* Digit value | 128 | 64 | 32 | 16 | 8 | 4 | 2 | 1 |

= Total (151) | 128 | 0 | 0 | 16 | 0 | 4 | 2 | 1 |

1001 0111 binary = 151 in decimal.

This can easily be extended to 16 or 32 bit binary numbers simply by adding more columns. Note that it’s easiest to start on the right end, and work your way left, multiplying the digit value by 2 as you go.

**Method 1 for converting decimal to binary**

Converting from decimal to binary is a little more tricky, but still pretty straightforward. There are two good methods to do this.

The first method involves continually dividing by 2, and writing down the remainders. The binary number is constructed at the end from the remainders, from the bottom up.

Converting 148 from decimal to binary (using r to denote a remainder):

148 / 2 = 74 r0

74 / 2 = 37 r0

37 / 2 = 18 r1

18 / 2 = 9 r0

9 / 2 = 4 r1

4 / 2 = 2 r0

2 / 2 = 1 r0

1 / 2 = 0 r1

Writing all of the remainders from the bottom up: 1001 0100

148 decimal = 1001 0100 binary.

You can verify this answer by converting the binary back to decimal:

(1 * 128) + (0 * 64) + (0 * 32) + (1 * 16) + (0 * 8) + (1 * 4) + (0 * 2) + (0 * 1) = 148

**Method 2 for converting decimal to binary**

The second method involves working backwards to figure out what each of the bits must be. This method can be easier with small binary numbers.

Consider the decimal number 148 again. What’s the largest power of 2 that’s smaller than 148? 128, so we’ll start there.

Is 148 >= 128? Yes, so the 128 bit must be 1. 148 - 128 = 20, which means we need to find bits worth 20 more.

Is 20 >= 64? No, so the 64 bit must be 0.

Is 20 >= 32? No, so the 32 bit must be 0.

Is 20 >= 16? Yes, so the 16 bit must be 1. 20 - 16 = 4, which means we need to find bits worth 4 more.

Is 4 >= 8? No, so the 8 bit must be 0.

Is 4 >= 4? Yes, so the 4 bit must be 1. 4 - 4 = 0, which means all the rest of the bits must be 0.

148 = (1 * 128) + (0 * 64) + (0 * 32) + (1 * 16) + (0 * 8) + (1 * 4) + (0 * 2) + (0 * 1) = 1001 0100

In table format:

Binary number | 1 | 0 | 0 | 1 | 0 | 1 | 0 | 0 |

* Digit value | 128 | 64 | 32 | 16 | 8 | 4 | 2 | 1 |

= Total (148) | 128 | 0 | 0 | 16 | 0 | 4 | 0 | 0 |

**Another example**

Let’s convert 117 to binary using method 1:

117 / 2 = 58 r1

58 / 2 = 29 r0

29 / 2 = 14 r1

14 / 2 = 7 r0

7 / 2 = 3 r1

3 / 2 = 1 r1

1 / 2 = 0 r1

Constructing the number from the remainders from the bottom up, 117 = 111 0101 binary

And using method 2:

The largest power of 2 less than 117 is 64.

Is 117 >= 64? Yes, so the 64 bit must be 1. 117 - 64 = 53.

Is 53 >= 32? Yes, so the 32 bit must be 1. 53 - 32 = 21.

Is 21 >= 16? Yes, so the 16 bit must be 1. 21 - 16 = 5.

Is 5 >= 8? No, so the 8 bit must be 0.

Is 5 >= 4? Yes, so the 4 bit must be 1. 5 - 4 = 1.

Is 1 >= 2? No, so the 2 bit must be 0.

Is 1 >= 1? Yes, so the 1 bit must be 1.

117 decimal = 111 0101 binary.

**Adding in binary**

In some cases (we’ll see one in just a moment), it’s useful to be able to add two binary numbers. Adding binary numbers is surprisingly easy (maybe even easier than adding decimal numbers), although it may seem odd at first because you’re not used to it.

Consider two small binary numbers:

0110 (6 in decimal) +

0111 (7 in decimal)

Let’s add these. First, line them up, as we have above. Then, starting from the right and working left, we add each column of digits, just like we do in a decimal number. However, because a binary digit can only be a 0 or a 1, there are only 4 possibilities:

- 0 + 0 = 0
- 0 + 1 = 1
- 1 + 0 = 1
- 1 + 1 = 0, carry a 1 over to the next column

Let’s do the first column:

0110 (6 in decimal) + 0111 (7 in decimal) ---- 1

0 + 1 = 1. Easy.

Second column:

1 0110 (6 in decimal) + 0111 (7 in decimal) ---- 01

1 + 1 = 0, with a carried one into the next column

Third column:

11 0110 (6 in decimal) + 0111 (7 in decimal) ---- 101

This one is a little trickier. Normally, 1 + 1 = 0, with a carried one into the next column. However, we already have a 1 carried from the previous column, so we need to add 1. Thus, we end up with a 1 in this column, with a 1 carried over to the next column

Last column:

11 0110 (6 in decimal) + 0111 (7 in decimal) ---- 1101

0 + 0 = 0, but there’s a carried 1, so we add 1. 1101 = 13 in decimal.

Now, how do we add 1 to any given binary number (such as 1011 0011)? The same as above, only the bottom number is binary 1.

1 (carry column) 1011 0011 (original binary number) 0000 0001 (1 in binary) --------- 1011 0100

**Signed numbers and two’s complement**

In the above examples, we’ve dealt solely with unsigned integers. In this section, we’ll take a look at how signed numbers (which can be negative) are dealt with.

Signed integers are typically stored using a method known as **two’s complement**. In two’s complement, the leftmost (most significant) bit is used as the sign bit. A 0 sign bit means the number is positive, and a 1 sign bit means the number is negative.

Positive signed numbers are stored just like positive unsigned numbers (with the sign bit set to 0).

Negative signed numbers are stored as the inverse of the positive number, plus 1.

**Converting integers to binary two’s complement**

For example, here’s how we convert -5 to binary two’s complement:

First we figure out the binary representation for 5: 0000 0101

Then we invert all of the bits: 1111 1010

Then we add 1: 1111 1011

Converting -76 to binary:

Positive 76 in binary: 0100 1100

Invert all the bits: 1011 0011

Add 1: 1011 0100

Why do we add 1? Consider the number 0. If a negative value was simply represented as the inverse of the positive number, 0 would have two representations: 0000 0000 (positive zero) and 1111 1111 (negative zero). By adding 1, 1111 1111 intentionally overflows and becomes 0000 0000. This prevents 0 from having two representations, and simplifies some of the internal logic needed to do arithmetic with negative numbers.

**Converting binary two’s complement to integers**

To convert a two’s complement binary number back into decimal, first look at the sign bit.

If the sign bit is 0, just convert the number as shown for unsigned numbers above.

If the sign bit is 1, then we invert the bits, add 1, then convert to decimal, then make that decimal number negative (because the sign bit was originally negative).

For example, to convert 1001 1110 from two’s complement into a decimal number:

Given: 1001 1110

Invert the bits: 0110 0001

Add 1: 0110 0010

Convert to decimal: (0 * 128) + (1 * 64) + (1 * 32) + (0 * 16) + (0 * 8) + (0 * 4) + (1 * 2) + (0 * 1) = 64 + 32 + 2 = 98

Since the original sign bit was negative, the final value is -98.

If adding in binary is difficult for you, you can convert to decimal first, and then add 1.

**Why types matter**

Consider the binary value 1011 0100. What value does this represent? You’d probably say 180, and if this were standard unsigned binary number, you’d be right.

However, if this value was stored using two’s complement, it would be -76.

And if the value were encoded some other way, it could be something else entirely.

So how does C++ know whether to print a variable containing binary 1011 0100 as 180 or -76?

Way back in section 2.1 -- Basic addressing and variable declaration, we said, “When you assign a value to a data type, the compiler and CPU takes care of the details of encoding your value into the appropriate sequence of bits for that data type. When you ask for your value back, your number is “reconstituted” from the sequence of bits in memory.”

So the answer is: it uses the type of the variable to convert the underlying binary representation back into the expected form. So if the variable type was an unsigned integer, it would know that 1011 0100 was standard binary, and should be printed as 180. If the variable was a signed integer, it would know that 1011 0100 was encoded using two’s complement (assuming that’s what it was using), and should be printed as -76.

**What about converting floating point numbers from/to binary?**

How floating point numbers get converted from/to binary is quite a bit more complicated, and not something you’re likely to ever need to know. However, if you’re curious, see this site, which does a good job of explaining the topic in detail.

**Quiz**

1) Convert 0100 1101 to decimal.

2) Convert 93 to an 8-bit unsigned binary number.

3) Convert -93 to an 8-bit signed binary number (using two’s complement).

4) Convert 1010 0010 to an unsigned decimal number.

5) Convert 1010 0010 to a signed decimal number (assume two’s complement).

6) Write a program that asks the user to input a number between 0 and 255. Print this number as an 8-bit binary number (of the form #### ####). Don’t use any bitwise operators.

Hint: Use method 2. Assume the largest power of 2 is 128.

Hint: Write a function to test whether your input number is greater than some power of 2. If so, print ‘1’ and return your number minus the power of 2.

**Quiz answers**

O.3.8 -- Bitwise operators |

Index |

O.3.6 -- Logical operators |

I know we still not cover the for loops, but what about this as solution for the excercise? Any remarks?

Hi Lorenz!

* Line 21: Initialize your variables with brace initializers.

* Line 21: Use --prefix unless you need postfix--

* @main: Missing return statement (?) (Code is missing).

Looks good otherwise.

Thank you!

All 3 mistakes because I'm coming from C for microcontrollers, I will keep in mind!

This is my code for problem 6. If anyone can give me some feedback that'd be much appreciated! thank you.

Hi!

* @readUserInput: Missing return-statement. Make sure you followed lesson 0.10 and 0.11.

* Avoid recursion (A function calling itself). You'll learn about alternatives later.

- This is my Program. I use While to find the bit value by comparing with pow(2,l).

Hi!

* Don't use "using namespace". It can lead to naming conflicts.

* Use ++prefix unless you need postfix++. It's faster.

* Don't use @system.

* Missing printed trailing line feed at the end of your program.

* @main can be moved below the other functions to avoid forward declarations.

* Inconsistent formatting. Use the auto-formatting feature of your editor.

* Line 14, 16, 28: Initialize your variables with brace initializers.

* C++ uses @std::flush or @std::endl to flush a stream. @fflush is C.

* Line 16: That's an array of vectors, not what you want. Read to lesson on @std::vector and arrays or keep your code simple until you get there.

* Line 18: @veca[8] doesn't exist. Behavior is undefined.

* @Binarybits: Missing return-statement. Make sure you followed lesson 0.10 and 0.11.

wondering if this is readable as is or should I be commenting it?

If you need non-documentation comments, your code is poor (or very complex).

* Use the auto-formatting feature of your editor.

* Line 9: Initialize your variables with braced initializers.

* Line 8, 23, 24, 30: Should be constexpr.

* Line 8, 30: Duplicate.

Separate constants and code, add some space, and your code will be fine.

Just posting this to see if there's any way to improve, or weak points in the code. If you notice any I'd love to hear what I can do better

Out of curiosity, if somebody entered "a" instead of a number when prompted for it, what command could I use to trigger some of my own code?

Also I'm an idiot and tried to "log in" like 100 times before realizing I don't need an account to comment and I was actually trying to log

in as a site admin the whole time. So if an actual admin sees this, sorry about that

Hi!

* Line 30: Initialize your variables with brace initializers. You used direct initialization.

* Line 5: Initialize your variables with brace initializers.

* Line 16, 17: Limit your lines to 80 characters in length for better readability on small displays.

* Don't use "using namespace".

* Don't use @exit.

* @std::cin.ignore without arguments will ignore only 1 character.

> if somebody entered "a" instead of a number

Extraction will fail. @std::cin.fail() will return true. Use @std::cin.clear() and @std::cin.ignore to bring the input stream back into a valid state.

This is also covered in a later lesson.

I hope this is a cleaner version. Could you elaborate "@std::cin.ignore without arguments will ignore only 1 character"?

I'm not sure if I understand the full use of @std::cin.ignore, aside from the fact it lets me use @std::cin.get()

so that I can view the results of my program without the console exiting upon completion. That's pretty much all

I know about @std::cin.ignore() and all I use it for as of right now.

In the future I'll try not to ask questions regarding future techniques, I should probably just finish all of

the lessons here so that nobody has to repeat themselves.

Thanks!

* Line 3: Initialize to 0

Let's say you enter "123abc" in line 3. 123 is stored in @i, "abc" remains in the input stream. Line 4 will try to extract "abc", but it can't be stored in an int, so the stream enters a failed state.

@std::cin.ignore(std::streamsize count, char delim) (@std::streamsize is an integer type) ignores all characters until it finds @delim or @count characters have been ignored.

By default, @count is 1. 'a' would be removed from the input stream, by "bc" remains.

Ideally, all characters should be removed, so line 4 prompts the user to enter a second number. You can do this by passing @std::numeric_limits<std::streamsize>::max() and '\n'.

@std::cin.ignore disables the count check when @std::numeric_limits<std::streamsize>::max() is passed. It will now ignore (remove) all characters until it finds '\n' (It also removes '\n', but then stops).

Is this any good?

Also, for some reason /n wont work.

Hi Nathan!

* Line 29: Initialize your variables with uniform initialization. You used direct initialization.

* Line 7: Initialize your variables with uniform initialization.

I'm trying to solve the last task for over than 2 hours now, but I can't find the problem. I think that the function insertNumber is making me problem but I don't how to change it.

You're not using the value returned by @calculating.

* Initialize your variables with uniform initialization

* All three functions are missing a return statement

* Signed/unsigned mismatch

* Don't use "using namespace"

* 225 != 255

Wow, what a rush does hahaha. However Thank You :)

ps. sorry for the bad english, its not my native.

Well here's my solution.I think there are few places where i can improve it.

I have a few off-topic questions:

Why should we initialize our variables ( I got in habbit of doing it, which is good) when we can acutally default initialize (e.g. int number {} ).As far as I understood it will default initialize to 0 (depending of the type I think, in this case an int 0 ).Or thats just for C++11?

Also I just cant understand where should we use " std::endl " and where "\n".I just dont get whats direct output, I guess thats because I have no previous experience with programing, who knows.

Anyways thanks for this tutorials, Alex,they are great.Also thanks for this community for sharing their codes.I learned much from them aswell and thats why i post mine(and also to be corrected if I got it wrong ). :)

Also thanks for nascardriver hes extremely helpful!

Hi!

> This is easy program and can be done with 2 functions or even 1

More functions usually mean better forward compatibility, reusability and maintainability.

> Why should we initialize our variables [...]

> As far as I understood it will default initialize to 0

It will. But if you explicitly initialize to 0, even a non-C++ developer can understand what's going on. Empty curly brackets might not be understood.

> Or thats just for C++11?

Uniform initialization was introduced in C++11. Before that, curly brackets could only be used to initialize lists.

> Also I just cant understand where should we use " std::endl " and where "\n"

When you use @std::endl, all output will be displayed in the console immediately.

When you use '\n', the output might stay in memory for a little while before it actually gets printed. @std::endl is slower than '\n'. Use '\n' unless you need immediate output.

> I think there are few places where i can improve it

* Only use conditional statements if you need to return value of the called functions. Use if-else-if-else otherwise.

* @calculateInBinary::status is unnecessary. You can pass false/true in line 68 and 73.

* Line 69: The value of @decimal_number is not used after this line. There's no reason to decrement it. A subtraction suffices.

Thanks for the reply nascardriver i really appriciate it,and implemented the suggestions.

Exept that I dont get the last one.

> Line 69: The value of @decimal_number is not used after this line[...]

*But the next function is using the returned value of expression decimal_number - 2^n;

You're right, the value is used. I should've said "@decimal_number is not used after this line".

This is what I meant

Hah, wow thats true.I really have no idea why I used arithmetic assignment instead of just decrement it.Thanks :)

How I did it (with for loop)

Hello! Would writing the power function like this (with only 1 return function) cause any unseen problems? Seems to work OK:

int power2(int x, int power)

{

if (x >= power)

{

std::cout << "1";

x = (x - power);

}

else std::cout << "0";

return x;

}

Hi Jon!

Nope, that's fine.

Please use code tags when posting code next time.

Here's my code:

Hi!

* Line 8: Initialize your variables. Bugs caused by uninitialized variables are hard to debug

* Don't use "using namespace". It can cause name collisions.

* @main is missing a return-statement.

As a point for readability. I would recommend not ending a sentence with a binary number and starting the next sentence with the same or another binary number. If someone happens to not see the period it can cause confusion in the interpretation.

ex. "Consider the 8 bit (1 byte) binary number 0101 1110. 0101 1110 means..."

It would be better as "Consider the 8 bit (1 byte) binary number 0101 1110. This binary number means..."

Agreed, and updated. Thanks!

"In the following examples, we assume that we’re dealing with unsigned integers."

Integers with 1 byte?

No, integers that are always positive. Revisit lesson 2.4.

But integers have 4 bytes (or 2 bytes minimum). I know unsigned doesn't have negative.

It doesn't matter how big the integers are. The binary representation of a number doesn't change based on integer size (the high bits are just padded with 0s).

For example, with a 4-bit integer, the number 3 is represented as: 0011.

With an 8-bit integer, the number 3 is represented as 0000 0011.

With a 16-bit integer, the number 3 is represented as 0000 0000 0000 0011.

"For example, to convert 1001 1110 from two’s complement into a decimal number:

Given: 1001 1110

Invert the bits: 0110 0001

Add 1: 0110 0010

Convert to decimal: (0 * 128) + (1 * 64) + (1 * 32) + (0 * 16) + (0 * 8) + (0 * 4) + (1 * 2) + (0 * 1) = 64 + 32 + 2 = 98

Since the original sign bit was negative, the final value is -98."

Where is the sign bit?

The first bit is the sign bit

The one that was inverted? Isn't it part of the number? Then why is unsigned 1 byte 0-255 and signed 1 byte 0-127?

For unsigned numbers, the first bit is part of the number.

For signed numbers, the first bit is the sign bit.

Signed 1 byte is -128 to 127.

In this case, 1001 1110, 1 is the sign bit, and 001 110 is the number, right? Then the sign bit shouldn't be inverted and the (0 * 128) part should be removed, as it is not part of the number, it's the sign bit. Right? Because if it was still part of the number then we would have 0-255 instead of 0-127, which is wrong for a signed byte.

> In this case, 1001 1110, 1 is the sign bit, and 001 110 is the number, right?

No. If the sign bit is set, you need to invert the entire number and add 1. Re-read the section about two's complement.

> Then the sign bit shouldn't be inverted and the (0 * 128) part should be removed

After inverting and adding 1, the first number could again be 1, but this time it's part of the number and no longer considered a sign.

> 0-127

There is no type with this range. It's either 0 to 255 or -128 to 127

"For example, to convert 1001 1110 from two’s complement into a decimal number:

Given: 1001 1110

Invert the bits: 0110 0001

Add 1: 0110 0010

Convert to decimal: (0 * 128) + (1 * 64) + (1 * 32) + (0 * 16) + (0 * 8) + (0 * 4) + (1 * 2) + (0 * 1) = 64 + 32 + 2 = 98

Since the original sign bit was negative, the final value is -98."

So when the byte is signed and the bit sign is 1, it will be able to be 0xxx xxxx, which will translate to a number between 0 and 127 (or 1 and 128 if you add 1). When bit sign is 0 (positive), it will be able to be 1xxx xxxx, which translates to between 128 and 255 (or 129 and 256 (0) if you add 1). So you can't have positive less than 128 (and bigger than 0)??

> when the byte is signed and the bit sign is 1, it will be able to be 0xxx xxxx

But you add 1, so it's either 0xxx xxxx or 1000 0000, but at least 0000 0001, which is 1 to 128, or -1 to -128, because the sign bit was negative. If the sign bit is 0, the range is 0000 0000 to 0111 1111 or 0 to 127.

> When bit sign is 0 (positive), it will be able to be 1xxx xxxx

You only invert if the sign bit is 1. If it's 0, the number stays as it is.

> You only invert if the sign bit is 1. If it's 0, the number stays as it is.

Well, then the "(0 * 128)" is optional, as it will always be zero.

Edit: Ahh, nevermind, I read what you said above about add 1.

Got it, thanks for helping.

1000 0000

sign bit is 1 -> invert

0111 1111

add 1

1000 0000

that's -128, the step is not optional.

Here is my code:

This is how I did it.

We can maybe cut down on the code by implementing arrays for each of the bits

I've wrote three functions: one for data input (unnecessary in this case), one for calculating the power of 2 and one for calculating and printing binary form and was so proud of myself. Then I've checked your solution and seen that it is so much more elegant and concise!

Hi!

Sorry if this outside the scope of this site, but I was wondering why we encode negative numbers this way.

If my understanding is correct, to write -5 in binary over a byte, we use 7 bits to write (-5 % 128) = 123, and add a 1 in front to indicate the number is negative. 0111 1011 is 123, so -5 is 1111 1011.

Ultimately, if we interpret the 1 in front as we do for unsigned numebrs, it's as if we replaced 251 by -5. So the sequence of numbers goes like this: 0,1,2... 127,-128,-127,... -1.

But doesn't this mean that -5 or any other negative number is not written the same way over 1 byte as it is over 2 bytes? Moreover, why do we use this particular sequence instead of another one? (for instance, 0,1,2...127,-1...-128, or even -128,-127,...127)

Agin, sorry to bother you with this, I realize it has nothing to do with actual coding. Thanks for your efforts!

Hi Jean!

> If my understanding is correct

I don't know if your way of conversion is correct, here's how I learned it:

The standard doesn't specify a specific negative number representation. Compiler developers are free to use other representations. The most common representation is two's complement (What I did above)

> But doesn't this mean that -5 or any other negative number is not written the same way over 1 byte as it is over 2 bytes?

That's what it means.

> Moreover, why do we use this particular sequence

The sequence is determined by the binary representation. You always have

And convert that into decimal. Naturally, 0 is the first number. When using two's complement, the number following 127 (0111 1111) is -128 (1000 0000).

>That's what it means.

Humm, that's a tad strange. Thanks a lot!