FRIHOST FORUMS SEARCH FAQ TOS BLOGS COMPETITIONS
You are invited to Log in or Register a free Frihost Account!


Integer to Binary





umeshtangnu
I'd like to write a real simple way to display an integer's binary equivalent. I've looked on the web but all the examples are too complicated. I did come across a Visual Basic example so I tried to convert it to C++. The code isn't bad but there are some problems. The biggest problem is that it prints the answer backwards. For example if I enter the integer 12 when I run the program instead of the compiler printing 1100, it will print 0011. Another thing I don't like is if I enter like say the integer 1, it will only print 1, not 0001. I would like the program to always print 4 positions. Actually if I could get the progam to always print 8 positions that would be better. So if I entered the integer 12, it would print 00001100. Here is what I got:

int main()
{
int n;

cout << "Enter an integer: ";
cin >> n;

while (n > 0)
{

if (n % 2)
cout << "1";

else
cout << "0";

n = n / 2;
}

cout << endl;

return 0;
}
snowboardalliance
instead of cout, could you just concatenate it on to a string? Then you could easily reverse it after and add the necessary 0s. I haven't used c++ in a while though so I don't know how well that would work.
Indi
You will have to trade-off simplicity vs. efficiency. Here's a very simple way to do it:

Code:
#include <algorithm>
#include <string>

std::string to_binary_string(unsigned long n)
{
   std::string result;
   
   do
   {
      result += (n & 0x1) ? '1' : '0';
   } while ((n >>= 1));
   
   std::reverse(result.begin(), result.end());
   
   return result;
}

// To use:
unsigned int number /* = whatever number */;
std::cout << to_binary_string(number);

Buuuuut not very efficient.

For an efficient way to do it that does not require temporaries and can write directly to an output stream in the right order, i'll give you a tip: use CHAR_BIT and sizeof to determine the maximum number of bits in your number, and check them in order. See if you can figure it out from there.

As for padding to make 1 come out as 0001, it's no problem to add to either method. For the first method, all you need is insert(). For the second, i'll leave that as an exercise.
qebab
I just had to reply with a recursive (but probably less efficient solution) as well, though this is C and I didn't feel like saving the thing in a char *, as it would have made things too complicated for the simple example:
Code:
void ToBin(unsigned long n)
{
     if (n == 1 || n == 0) {
     printf("%d", n);
     } else {
     ToBin(n / 2);
     printf("%d", n % 2);
     }
}


I wrote this just now, so I hope I didn't do any mistakes, but I don't want to guarantee it.

The same algorithm in python:
Code:

def to_bin(n): return str(n) if n in (0, 1) else to_bin(n / 2) + str(n % 2)


Which can of course be expanded upon to handle other number systems besides binary:
Code:

def to_unar(num, numsys): return str(num) if num in range(numsys) else to_bin(num / numsys) + str(num % numsys)


Simple, and easy to grasp. Recursion can be nice sometimes.

Edit: Actually, this is the exact same thing as Indi and umeshtangnu posted above, just recursive. My apologies!
Indi
qebab wrote:
I just had to reply with a recursive (but probably less efficient solution) as well, though this is C and I didn't feel like saving the thing in a char *, as it would have made things too complicated for the simple example:
Code:
void ToBin(unsigned long n)
{
     if (n == 1 || n == 0) {
     printf("%d", n);
     } else {
     ToBin(n / 2);
     printf("%d", n % 2);
     }
}


I wrote this just now, so I hope I didn't do any mistakes, but I don't want to guarantee it.

The same algorithm in python:
Code:

def to_bin(n): return str(n) if n in (0, 1) else to_bin(n / 2) + str(n % 2)


Which can of course be expanded upon to handle other number systems besides binary:
Code:

def to_unar(num, numsys): return str(num) if num in range(numsys) else to_bin(num / numsys) + str(num % numsys)


Simple, and easy to grasp. Recursion can be nice sometimes.

Edit: Actually, this is the exact same thing as Indi and umeshtangnu posted above, just recursive. My apologies!

Did you try it? ^_^

Try writing a simple test program to test that function, and see what happens. ^_-
qebab
Ah, yeah, I see my mistake. Format strings >.<
Indi
Tch, i know you C hackers would rather give up a limb then let go of your printf(), but sometimes it's not really the best tool for the job. ^_- Your solution is actually really clever, but those printf()s just grate on me.

Take this case, for example:
Code:
if (n == 1 || n == 0)
{
   printf("%d", n);
}

Now without reading another line of code, you know automatically that this snippet can only output two possible things: 1 or 0. Each is a single character. There's no need for string functions, and there's certainly no need for formatting functions. If you did this:
Code:
if (n == 1 || n == 0)
{
   putchar(n ? '1' : '0');
}

That simple change will make that snippet easily 10 times faster. There will be no need for memory accesses, looping to check for '\0', or scanning for format codes.

Do the same on the other line to get:
Code:
void ToBin(unsigned long n)
{
   if (n == 1 || n == 0)
   {
      putchar(n ? '1' : '0');
   }
   else
   {
      ToBin(n / 2);
      putchar((n % 2) ? '1' : '0');
   }
}

Which will be significantly faster... and clearer, too, i think.

But you know... for the record:
Code:
void ToBin(unsigned long n)
{
   if (n > 1)
      ToBin(n / 2);
   
   putchar((n % 2) ? '1' : '0');
}

Sexy.
qebab
You are obviously right. I'm still a beginner when it comes to C, so there are a lot of things I simply don't see. Obviously, the last function you posted is a winner.

Edit:

And of course, this can easily be expanded upon as follows:

Code:

/* Where system is whatever numbersystem you want to use. */
void ToOther(long number, int system)
{
    if (number > (system - 1) {
        ToOther(number / system, system);
    }
    /* Maybe there's a better way to do this, but I don't see one. */ 
    printf("%c", (int) (number % system));
}


Yeah, the last one you wrote is very elegant and easily expanded on. Applause
qebab
This shows a possible approach to your padding and such as well, but is probably horribly inefficient:

Edit: This has a better format and seems more sensible.

Sample:
Quote:

robb@robb-laptop:~$ ./play 1010 101 32812 129 32
0000000000100000
0000000010000001
1000000000101100
0000000001100101
0000001111110010
Indi
qebab wrote:
You are obviously right. I'm still a beginner when it comes to C, so there are a lot of things I simply don't see. Obviously, the last function you posted is a winner.

Edit:

And of course, this can easily be expanded upon as follows:

Code:

/* Where system is whatever numbersystem you want to use. */
void ToOther(long number, int system)
{
    if (number > (system - 1) {
        ToOther(number / system, system);
    }
    /* Maybe there's a better way to do this, but I don't see one. */ 
    printf("%c", (int) (number % system));
}


Yeah, the last one you wrote is very elegant and easily expanded on. Applause

Weeeeelllll... ^_^; i wish i could take credit for that, but it really isn't so easy. Few things in life are unfortunately.

For starters, i have to fix a little glitch in your fixed version - it only works for bases from 2 to 10. If you try to print decimal 255 in hexadecimal using "ToOther(255, 16)", you're going to get something like "1515" instead of "ff".

To fix that, you need a helper function:
Code:
char digit(unsigned long num)
{
   static char const digits[] =
   {
      '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', // Covers 0-9
      'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', ..., // Alphabet covers 10-35
      'α', 'β', 'γ', 'δ', 'ε', 'ζ', 'η', 'θ', 'λ', ..., // Maybe Greek letters next, then who knows?
   };
   
   // Might want to assert that num < sizeof(digits) for safety
   
   return digits[num];
}

/* Where system is whatever numbersystem you want to use. */
void ToOther(long number, int system)
{
    if (number > (system - 1) {
        ToOther(number / system, system);
    }
   
    putchar(digit(number % system));
}


Now "ToOther(255, 16)" will give you "ff" as you would expect (and once again, you're not using the printf(), so it's much faster).

Buuuuut....

Life's never that convenient. ^_^; In reality, other bases don't always follow that pattern when using different bases. From what you know:
Code:
Base 2 (binary)      : 01
Base 8 (octal)       : 01234567
Base 10 (decimal)    : 0123456789
Base 16 (hexadecimal): 0123456789abcdef

So you would think that base 64, widely used on teh intarnets, would be: "01234546789abcdef...wxyzαβγδεζηθλ...so on to get 64 characters".

In reality, the most commonly used form of base 64 is: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/". Note that A = 0, B = 1, and a = 26.

Also, there are other deviations, like base 26, which commonly uses just the letters of the alphabet a-z, and base 32, which uses "abcdefghijklmnopqrstuvwxyz234567".

That's the reason that the C++ standard doesn't include a basic "to_any_base" function. It includes bases 8, 10 and 16 because they are almost universally standardized - especially in computing - but for some strange reason i can't fathom, it doesn't include base 2.

As for the padding and filling, i couldn't see your example - rafb only holds on to pastes for like a day or two. But C++ iostreams have facilities to automate padding and filling - the catch is that you will have to give up the idea of writing to the stream directly using the recursive method you came up with and go back to something a little more conventional - because with the recursive method, there is no way to predict in advance how many characters will be written.
qebab
Okay, I didn't think about that. I'll just post here and try to explain how I thought about it and hope for some more constructive critisism.

If we want padding (in C), we obviously can't use putchar, as we won't know how many digits we will be outputting until we're done and we need to do things in the right order. I understood it so that the original poster wanted something that will do this:
bin 4 => 00100
bin 3 => 00011
bin 9 => 01001

and so on.

We're going to have to use a character array to do this in C, so the declaration of our ToBin will look like this:
Code:
 int ToBin(char *dst, long num, int pos);


It'll make sense in a bit, I promise!

I've decided to write it as a commandline tool:

Code:

#include <stdio.h>
#include <math.h>
#include <string.h>
#include <stdlib.h>

/* I don't know where the functions I use are located, so I include a lot more than needed, unfortunately... */

#define SIZE 17

int ToBin(char *dst, long num, int pos);

int main(int argc, char **argv)
{
    if (argc > 2) {
        char result[SIZE];
        while (argc > 1) {
             long num = atol(argv[--argc]);
             int pos = SIZE - 2;
             int i;
             /* Fill the string with zeros and terminate it for every argument. */
             for (i = 0; i < SIZE - 2; i++) {
                 result[i] = '0';
             }
             result[SIZE - 1] = '\0';
             /* ToBin will signal error by returning 0. */
             if (ToBin(result, num, pos)) {
                 printf("%s\n", result);
             }
             else {
                 /* There was an error, this can only mean that the number was too large. */
                 printf("Number is too large, maximum is %ld.\n", (long) pow(2, SIZE - 1) - 1);
             }
         }
    }
    else {
        /* The user doesn't know what the program does!! */
        printf("Usage: ./bin num num... => num(base 2)...\n");
    }
    return 0;
}


That's the interface done, now I only need ToBin to work properly.

Code:

int ToBin(char *dst, long num, int pos)
{
    if (num) {
        if (pos < 0) {
            /* We're running off the end of the array... */
            return 0;
        }
        if (!(ToBin(dst, num / 2, pos - 1)) {
            /* A call further down the line ran off the end... At the same time, we modify the string with the successful calls, if any. */
            return 0;
         }
         dst[pos] = '0' + num % 2;
         /*If we got this far, it means success and we can signal that to the caller. */
     }
     return 1;
}


I hope it won't make you choke, but at least this will do what the OP asked for.
Indi
No, it's not bad. Just about the only things i'd change is replacing:
Code:
for (i = 0; i < SIZE - 2; i++) {
   result[i] = '0';
}

// with
memset(result, '0', SIZE - 2);

And replacing:
Code:
// This assumes that '0' + 1 gives '1', which is not necessarily true
dst[pos] = '0' + num % 2;

// And anyway, this would be faster
dst[pos] = (num % 2) ? '1' : '0';


---------------------------------------------------

For C++, i would probably use a manipulator "binary(unsigned long)" that works like this:
Code:
cout << "Printing binary number: " << binary(42) << endl;
// Will print: "Printing binary number: 101010"

// To set the width or the fill or the alignment, you would use the normal, built in methods
cout.width(8);
cout << "Printing binary number: "
      << right // right alignment
     << setfill('x')
     << binary(42) << endl;
// Will print: "Printing binary number: 101010xx"


To actually write the manipulator, aside from the boilerplate code, i would step through each bit from left to right. The stream parameters i would have to check are:
  • left and right: alignment.
  • showbase and noshowbase: base prefix - probably 'b'.
  • uppercase and nouppercase: if there's a base prefix, use 'b' or 'B'.
  • fill: the fill character.
  • width: width.
Which really isn't all that much.

Then i suppose i would proceed like this:
  1. Test for "ostream.flags() & ios_base::showbase", and if set, then do "ostream.put((ostream.flags() & ios_base::uppercase) ? 'B' : 'b');".

  2. Loop through the bits left to right to count the leading zeros.

  3. If "stream.width()" is greater than what's left and "ostream.flags() & ios_base::right", then fill up the difference with "ostream.fill()".

  4. Loop through the bits again, starting from the first non-zero bit (if any), and print them out.

  5. If "stream.width()" is greater than what's left and "ostream.flags() & ios_base::left", then fill up the difference with "ostream.fill()".

That should make it behave as expected in C++ - handling padding, filling, alignment and all that neat stuff automatically - and it should be pretty fast, with no extra buffers required.
Related topics
from integer to binary
Decimal, Binary and Hexadecimal
Fortran Tutorials(77)
MySQL Masters Binary Logs & Replication?
writing COM components in Perl
help with an algorithm
Pixels
which one programming lanuge result's the best speed
build Universal Binary version of mysql administrator
Visual Basic Tutorial - File I/O in VB: Text Files
How do you upload in Ascii mode and binary mode and whats th
some questions - (write in binary and zip)
th 2038 bug and google
I Learned Binary Today :D
Reply to topic    Frihost Forum Index -> Scripting -> Others

FRIHOST HOME | FAQ | TOS | ABOUT US | CONTACT US | SITE MAP
© 2005-2011 Frihost, forums powered by phpBB.