Decimal to Binary only using iostream standard library without arrays or string

First of all, I know that there are already a lot of question answered on this topic. But as far as I’m concerened I’ve never seen this exact problem. I’ve been asked to write a program that inputs a natural number and outputs the binary digit in correct order. So far, very simple, I know… The big problem for me is that I’ve seen the solutions using strings, arrays and other libraries than the standard iostream. But I cannot think of a solution where I do not have to use strings, arrays and other libraries. In my opinion I have to start the conversion with the most significant bit, but how do I do that? Can somebody please give me a hint? Thank you

int main()
{
  int n;
  int a;

  std::cout << "Please enter a number: ";
  std::cin >> n;

  while (n != 0)
  {
      a = n % 2;
      n /= 2;
      std::cout << a;
  }
  std::cout << std::endl;

  return 0;
}

Answer

When you get down to basics, all you need is the >> operator to repeatedly shift the number to the right by one until you run out of bits. (right shift by 1 is the same as dividing by 2, but less computationally expensive). In your case, to output the binary representation of any number, you will just loop over each bit, and test if the bit is 0 or 1. If it is 0, you output the character '0', if it is 1, you output the character '1'.

The only caveat is when you loop shifting by 1 you obtain the Least Significant Bit first, but when you normally think of printing a number, you output the Most Significant Bit first. Not a problem. You either (1) use a recursive function as suggested which will have the effect of reversing the order the bit representation is output, or (2) loop from the number of bits to zero shifting by that value each time — which also has the effect of reversing the order the representation is output.

Recursive Approach

A recursive approach is dead-bang simple. You just loop while the value isn’t zero and with v as your value, you pass v >> 1 as the parameter in your recursive call. You then use a simple ternary (shorthand if .. else ..) to test if the least significant bit remaining is 1 or 0 using the & operator (e.g. num & 1 != 0 the least significant bit is 1, otherwise its 0). So your recursive function to print the binary representation of a value can be:

#include <iostream>

/* recursive funciton to output binary representation of v */
void binrec (uint64_t v)
{
    if (!v)                                 /* exit condition */
        return;
    
    binrec (v >> 1);                        /* recursive call */
    std::cout.put (v & 1 ? '1' : '0');      /* output */
}

but there is a wrinkle… you have to handle the v == 0 case separately. In the function above, you output nothing when v == 0. So, the easiest way to handle it is just to write a helper-function that checks if v == 0 and if so, outputs '0' and returns, otherwise it calls your recursive function. Your helper can be:

/* helper function to handle 0-case, then call binrec() */
void binstr (uint64_t v)
{
    if (!v) {                               /* handle 0-case */
        std::cout.put ('0');
        return;
    }
    
    binrec (v);                             /* call recursive function */
}

In your code, you simply call binstr (v) to output the binary representation of the number.

Non-recursive Approach

A non-recursive approach, allows the whole process to be handled in a single function. However, since you cannot rely on recursion to reverse the order of the output, you need to work backward from the number of bits to zero, shifting by the current amount to test the bit at that index. That has the same end-effect as the recursion in reversing the order of output giving you the correct output.

The only caveat here is if you only want to output bits used in the number. For example in the number 10, you output the binary of 1010 instead of 00001010. (you can do it either way, but for purposes here, the output discards bits that do no contribute to the value) Since you are shifting to the right by the largest value first, you simply ignore outputting a 0 when the shifted value is 0. You only start the output when the remaining bits have a value. You can do that as:

#include <climits>

/* non-recursive output of binary representation of v */
void binstr (uint64_t v)
{
    size_t bits = sizeof v * CHAR_BIT;              /* no. of bits */
    uint64_t rem = 0;                               /* remaining bits non-zero */

    if (!v) {                                       /* handle 0-case */
        std::cout.put ('0');
        return; 
    };

    while (bits--)                                  /* loop bits times in reverse */
        if ((rem = v >> bits))                      /* when rem value is non-zero */
            std::cout.put (rem & 1 ? '1' : '0');    /* output bit representation */
}

(the zero-case is handled within this single function)

You can write a small main() that allows you to pass the value to convert as the first argument to the program in either decimal or hex format (10 by default if no argument is given) and the program will output the binary representation of the value.

(Just include whichever set of functions you want to test. You can also use preprocessing conditionals to choose that automatically at compile time, but to avoid the confusion that would interject — just copy/paste for now)

int main (int argc, char **argv) {
    
    long n = argc > 1 ? std::stol (argv[1], 0, 0) : 10;
    
    if (errno)
        return 1;
    
    binstr (n);
    std::cout.put ('n');
}

(note: you should actually use try {...} catch {...} exception handling to formally validate the std::stol() conversion, but errno is valid for a quick check as well)

Example Use/Output

Hex input format:

$ ./bin/bin_recursive 0xff
11111111

Default 10 if no argument:

$ ./bin/bin_recursive
1010

Decimal formatted argument:

$ ./bin/bin_recursive 391431
1011111100100000111

Look things over and let me know if you have further questions.

Leave a Reply

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