Search

3.7 — Converting between binary and decimal

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 numbers (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. 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

1) Show Solution

2) Show Solution

3) Show Solution

4) Show Solution

5) Show Solution

6) Show Solution

3.8 -- Bitwise operators
Index
3.6 -- Logical operators

257 comments to 3.7 — Converting between binary and decimal

  • Luhan

    What could I do to make my code more readable, and easy to understand?

  • Khanh

    Hi Alex, I really like your tutorial. My English is not my first language so it made me a little confused but it is fine now, this one took me at least 30-45 mins for thinking and checking on papers. But finally, I got it by myself.

    #include "stdafx.h"
    #include <iostream>

    int getNumber()
    {
        std::cout << "Enter a number: ";
        int x;
        std::cin >> x;

        return x;
    }

    int binaryNumber(int x, int digitValue)
    {
        if (x >= digitValue)
        {
            std::cout << 1;
            return x - digitValue;
        }
        else
        {
            std::cout << 0;
            return x;
        }
    }

    void printBinary(int x)
    {
        x = binaryNumber(x, 128);
        x = binaryNumber(x, 64);
        x = binaryNumber(x, 32);
        x = binaryNumber(x, 16);

        std::cout << " ";

        x = binaryNumber(x, 8);
        x = binaryNumber(x, 4);
        x = binaryNumber(x, 2);
        x = binaryNumber(x, 1);

        std::cout << "n";
    }

    int main()
    {
        int x = getNumber();
        printBinary(x);

        return 0;
    }

  • Lucas

  • Kevin B

    I had trouble with converting Decimal 93 to 8-bit Binary.

    Eventually I figured I missed the most significant digit! Silly me…

    93 / 2 = 46  r  1
    46 / 2 = 23  r  0
    23 / 2 = 11   r  1
    11  / 2 = 5    r  1
    5   / 2 = 2    r  1
    2   / 2 = 1    r  0
    1   / 2 = 0    r  1  ( <- This is what I forgot to do.)

    0101 1101  = 29

    Using the second method…

    93 >= 64? Yes,  1.   93 - 64 = 29
    29 >= 32? No,   0.
    29 >= 16? Yes,   1.  29 - 16 = 13
    13 >=  8? Yes,    1.   13 - 8 = 5
    5  >=   4? Yes,    1.    5 - 4 = 1
    1 >= 2? No,        0.
    1 >= 1? Yes,        1. ( <- This is what I forgot)

    0101 1101 = 93

    This lesson was good to learn (I didn’t touch a line of C++ code!)

  • ukijo

    in the quizz, the 6th question, how (x - pow) is considered as x after by the compiler?

  • ScarLet

    Hi Alex,

    Can you tell me how to covert double variable?
    ex: double x(3.1412313e3);

  • Jeremy

    I didn’t see to use method 2 so I did this:

  • ScarLet

    I wonder how the floating value converted into binary?
    like variable double x(3.141);
    How to converted it into binary?

  • Xavier

    hahaha "We talked a little bit" (second sentence, first paragraph)

  • Taksh

    I was wondering what is wrong with my below code. Thanks in advance.

  • Taksh

    Hey ALex,

    In solution of Q.6., you used int pow as a  parameter in the function however you did never defined int pow.

  • Peter B

    I feel so stupid now. I used to study C++ from other tutorials which were actually inferior to this one (that’s why I’m here) so I used that knowledge to complete Quiz #6. So I used arrays and for loops in order to have the program do everything for me. Still, compared to the simplistic way you code, my program is so much worse than yours. At least I can see there’s still plenty for me to learn and to improve on. Also, your examples let me take knowledge out of them so I appreciate it. Thank you very much for those tutorials. I feel like I can gain profound knowledge out of this.

  • Cotrim

    And here goes my take on it (again I complicated sorry xD)

  • Anshuman Singh

    I think this is a better way as it can be modified to convert even bigger decimal numbers to binary easily.

  • manikanth

    Hello Alex sir,
    i have two doubts one related to pointers and other is related to ascii in below code.

    point 1:when am trying to print the output result is ‘W’ for print f statement and how come 1111 prints W (when given % c) ?
    point 2: pointer stores the address of other variable so address in numerical format so why i cannot assign numericals to pointer?

    • Alex

      1) %c means treat the value as a character, with range -128 to 127. 1111 is outside that range, so you’re getting overflow. That overflow is resulting in integer 87, which is character ‘W’.

      2) You can’t have a pointer hold the address of a literal, which is an r-value (and thus, doesn’t have a permanent address).

  • AMG

    Quiz 6). Comments to your answer. I thought "using namespace std;" is very convenient, but you did not use it. Why? Why two identical "if" statements are not combined? As always, fascinated by your efforts.

    • Alex

      using namespace std; is generally bad practice because it significant increases the risk of naming collisions. I discuss this more in chapter 4.

      I used two almost-identical if-statements only because I haven’t covered compound statements (blocks) yet. I cover those in… chapter 5 I think.

  • Ryan

    Using some prior knowledge of loops and arrays (as well as that nice ?: operator a few sections back), I tried to get as "clean" an answer for question six as I could. I’m not sure how actually efficient this solution is, but it worked nonetheless:

    (Didn’t add a check for an invalid input however, but hey.)

  • Caitlyn

    I am sorry but i do not quite get it
    int main()
    {  
        signed int a = 180;
        std::cout<<(int)a;
        return 0;
    }
    This is my program, and the output i get in g++ is 180 regardless of wheter i use int or signed int. Can you please help me out here?

    • Alex

      You used an int here, which is probably 4 bytes on your system. You need to use a data type that’s only 1 byte. that’s why I suggested char.

      This prints -76.

  • Caitlyn

    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.

    My doubt is: isnt ‘int’ by default ‘signed int’? so if the number i had entered was x = 180; , wont the compiler assume that it is -76, considering its type is signed int?

    Thankyou

    • Alex

      Yes, integers in C++ default to signed. So an 8-bit signed integer (range -128 to 127) that assigned values 180 would print as -76. You can try this yourself with a signed char (static_cast it to an int before printing so it prints as an int instead of a char).

  • Eric

    When thinking about the question I could only think of storing the info in an array. I was thinking that that it would be easy to scale as well (if you wanted to do larger numbers). If you have any advice I would appreciate it.

  • Jim Smith

    While doing my homework assignment I wanted to complicate things, in the spirit of learning. So… I decided I wanted my program to let the user input anything and output the binary representation of that input (if the user entered an integer) or display an error message (if the user enters garbage or an integer that is out of range). I got carried away in my homework and the result is 200 lines of code (well… including comments).

    I have a feeling that my program is not as efficient as it could be. Any ideas about how to make it more concise and efficient are welcome. I would also want to know if my comments or identifiers could be improved.
    https://pastebin.com/a6Ayg4xf

  • Jeremiah

    ctrl + F "the the compiler"

    I assume you only intended to use "the" once.

  • Alex

    So you said in two’s complement, the most significant bit 0 = positive and 1 = negative.

    What about large numbers like -211?
    211 = 1101 0011
    The inverse +1 = 0010 1101

    Even though it’s meant to be -211, the binary still starts with a 0…or are you unable to use two’s complement after a certain point?

    • Alex

      -211 requires 9 bits to store. This is because unsigned and signed numbers have different ranges.

      With an unsigned number, the range is 0 to 255, so as you’ve noted, 211 = 1101 0011. However, with a signed number, half of the range goes to negative numbers, so the range is only -128 to 127. This means -211 is out of range of an 8-bit signed number, and requires an extra bit.

      The proper conversion would be 211 = 0 1101 0011 inverted + 1 -> 1 0010 1101

      • Alex

        Okay! That makes sense. I was thinking that might be the case but wasn’t completely sure…and now that I think about it, it was kinda covered in an earlier chapter. I appreciate the feedback.

  • Christoph

    What can i do to put the outputs into the right order.
    Btw i used the 1st method because i tried the 2nd method yesterday and failed miserably so i looked at the solution. I didn’t wanted to cheat myself so i tried to do it with the 1st method today. Help would be appreciated. Thanks

    • Alex

      Reversing the bit numbers is non-trivial given the concepts we’ve covered so far. Probably the easiest way is to put them into a std::string and then print the string when you’re done.

  • felipe

    5. Convert 1010 0010 to a signed decimal number (assume two’s complement).
    I think it would be easier to also teach people to just solve the reverse version of the unsigned binary and just add 1 to the answer?
    For me it was much easier to understand, I just did the table for 0101 1101 = -93 then just add 1 = -94.

  • Mohsen

    i wrote my own program and its working perfect.
    if you have any suggestion please tell me.

  • James Ray

    While I did first implement working code using only theory provided previously, I also figured out how to do quiz question 6 using a while statement:

    • James Ray

      Unfortunately I couldn’t figure out a better workaround for using the pow(base, exponent) function than having separate input parameters for the exponent as double and int types, using each type where appropriate (exponent for the pow() function and int for the modulus operator), and decrementing each variable at the end of the loop.

  • Tim

    So this may not be the right place to ask since this is more of a background of C/C++ question rather than a question about programming in C/C++, but why all the bit flipping for negative numbers? Wouldn’t it be easier to just look at the leftmost bit to determine positive or negative and call it a day? i.e. 1011 and 0011. The last three digits of both being the same. Wouldn’t it be easier to just say both are 3, the only difference being the first starts with a 1 making it -3?

    • Alex

      Negative numbers are stored as the inverse of the positive numbers so that when you add a positive and a negative number, you get 0. It makes doing math with such numbers much easier.

  • Just wondering, why would we need to know this in the future?

  • css

    Could you explain why we return x - pow ?

    • Alex

      In the second method, when a bit is determined to be a “1”, you subtract out the value of that bit (pow) so you know how many more bits of value you need to find.

      In the lesson, it’s the doing the equivalent of this line:

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

      That “148 - 128” part is “x - pow”, leaving you with 20 remaining that you need to find bits for.

Leave a Comment

Put C++ code inside [code][/code] tags to use the syntax highlighter