I'm trying to convert a number from any base between 2-36 to any base between 2-36. I have the conversion to base 10, but I'm having trouble getting it from base 10 to the desired base. Any ideas? I know part of this idea will work, I just can't get it all together syntatically.
And don't worry about the checks (user inputs number 13, base 2), I'll add that at the end. Thanks!

#include <iostream>

using std::cout;
using std::cin;
using std::endl;

int ToTen ( char number[15], int base, int newbase );
void ToNewBase ();

int main()
{
    char number[15];
    int base = 0,
        newbase = 0,
        again = 0;

    //do
    //{
    cout <<"Enter number: ";
    cin >> number;
    _strupr_s(number);

    cout <<"Enter base of number (2-36): ";
    cin >> base;

    cout <<"Enter base you wish to convert to (2-36): ";
    cin >> newbase;

    ToTen ( number, base, newbase );

    return 0;
}

int ToTen ( char number[15], int base, int newbase )
{
    base;
    newbase;
    number[15];
    char newnumber[100];
    int answer = 0,
        newanswer = 0,
        i = 0,
        k = 0,
        digit = 0;
    short placevalue = 0;


    while ( number[i] != '\0' )
    {
        //for base 0-9
        if ( number[i] <= '9' && number[i] >= '0' )
            placevalue = number[i] - 48;
        //for bases 10-36
        else
            placevalue = ( number[i] - 65 ) + 10;

        answer = answer * base + placevalue;
        i++;
    }

    cout<< "base ten: " << answer<< '\n';

    while ( newnumber[k] != '\0' )
    {
        digit = answer % 10;
        newnumber[k] = ( answer / 10 );
        k++;
    }

    _strrev(newnumber);

    cout << newbase << ": " << newnumber;

    return 0;
}

Recommended Answers

All 4 Replies

Since you are coding in C++, why don't you use C++ string to hold your 'numbers' ... of ANY LENGTH?

You do show some nice style in your coding ...

But ... it is NOT good to use NON standard code ... as a general practice ... you want to have skill in coding PORTABLE code ... code that conforms to the present C++ standard.

You might like to see this edit of your code, with some fixes ...

Keep up the neat coding you are doing ... it sure makes it a joy for others to read :)

// newStudentConversion.cpp //

#include <iostream>
#include <string>
#include <cctype> // re. toupper

#include <algorithm> // re. reverse ...

using std::cout;
using std::cin;
using std::endl;
using std::flush;
using std::string;


int takeInInt( const string& msg, int min = 0, int max = 100,
                                const string& errMsg = "\nError!\n" )
{
    int val;
    while( true )
    {
        cout << msg << flush;
        if( cin >> val && cin.get() == '\n' && val >= min && val <= max )
            break;
        else
        {
            cout << errMsg;
            cin.clear();
            cin.sync();
        }
    }
    return val;
}

char takeInChr( const string& msg )
{
    cout << msg << flush;
    string reply;
    getline( cin, reply );
    if( reply.size() )
        return reply[0];
    // else ...
    return 0;
}

bool more()
{
    if( tolower( takeInChr( "More (y/n) ?" ) ) == 'n' )
        return false;
    // else ...
    return true;
}

bool isvalid( const string& s, int base )
{
    // char bot = '0';
    char top;
    if( base <= 10 ) top =  '0' + base-1;
    else top = 'A' + base-11;

    if( base <= 10 )
    {
        for( int i = s.size() - 1; i >= 0; --i )
            if( s[i] > top || s[i] < '0' ) return false;
        // else ... if reach here ...
        return true;
    }
    else
    {
        for( int i = s.size() - 1; i >= 0; --i )
            if( s[i] < '0' || s[i] > top  ||  (s[i] > '9' && s[i] < 'A') )
                return false;
        // else ... if reach here ...
        return true;
    }
}


// converts and shows input number in base TO  newbase ...
const string toNewBase( const string& number, int base, int newbase );




int main()
{
    const string errMsg = "\nEntry ERROR!  ONLY int values in "
                          "range 2..36 accepted here ... \n";
    do
    {
        int base = takeInInt( "Enter base of number "
                              "to convert (2-36): ", 2, 36 , errMsg );

        cout << "Enter number: ";
        string number;
        getline( cin, number );

        if( !isvalid( number, base ) )
        {
            cout << "\nEntry ERROR!  NOT a valid base " << base
                 << " number.\n";
            continue;
        }

        int newbase = takeInInt( "Enter base to which you wish "
                                 "to convert (2-36): ", 2, 36, errMsg );

        string newnumber = toNewBase( number, base, newbase );

        cout << "base "<< newbase << " = " << newnumber << endl
             << "string length = " << newnumber.size() << endl;
    }
    while( more() ) ;
}



const string toNewBase( const string& number, int base, int newbase )
{
    long long unsigned answer = 0;

    int len = number.size();
    for( int i = 0; i < len; ++i )
    {
        int placevalue = 0;

        //for base 2-9
        if( number[i] <= '9' && number[i] >= '0' )
            placevalue = number[i] - '0';
        //for bases 10-36
        else
            placevalue = toupper( number[i] ) - 'A' + 10;

        answer = answer * base  +  placevalue;
    }

    cout << "base 10 = " << answer << '\n';

    string newnumber;

    if( answer == 0 ) newnumber = "0";
    else while( answer )
    {
        int digit = answer % newbase; // get next digit ...

        // append to string converted to ASCII char value ...
        if( digit <= 9 )
            newnumber +=  digit + '0';
        else
            newnumber +=  digit - 10 + 'A';

        answer /= newbase;
    }

    reverse( newnumber.begin(), newnumber.end() );

    return newnumber;
}

One way to make your coding more efficient is to use a string to represent the digits that may be encountered:

const string digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";

Now for any base the value of a particular digit can easily be converted to the appropriate symbol just by using the index of digits(Hex 'F' has a value of 16 and equals digits[16]). This eliminates a lot of the math operations everytime you output a digit.

To simplify the rest of your code a function to convert any base to base 10 and then another to convert from base 10 to any base, breaks the problem up into more manageable pieces:

#include <iostream>
#include <sstream>
#include <math.h>

using namespace std;

const string digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
string PadLeft(string input, int totallength, char character)
{
    string output(totallength-input.length(),'0');
    return output + input;
}
string ToBaseX(int input, int base)
{
    stringstream output;
    output << digits[input % base];
    input /= base;
    while(input > 0)
    {
        output.seekp(0);
        output << digits[input % base] << output.str();
        input /= base;
    }

    return output.str();
}
int ToBase10(string input, int base)
{
    int length = input.length();
    int output = 0;
    int temp = 0;
    for(int i = 0; i < length; i++)
    {
        stringstream ss;
        ss << input[(length - 1) - i];
        ss >> temp;
        output += pow(base,i) * (digits[temp] - 48);
    }
    return output;
}
string BaseConverter(string num, int from, int to)
{
    return ToBaseX(ToBase10(num,from),to);
}
string BaseConverter(int num, int from, int to)
{
    stringstream ss;
    ss << num;
    return BaseConverter(ss.str(),from,to);
}
int main()
{
    string temp = PadLeft(BaseConverter(123456,8,20),6,'0');
    cout << temp;
    return 0;
}

I included a simple string padding function to standardize the length of the output string and an overload so that you can start with a number or a string.

A further note, to keep things simple I omitted any limit, type, or format checking.

@tinstaafl ... a Dani Virtuoso indeed ... very well designed and developed ... and demos the efficent code that can be often obtained by the use of tables.

This variant, with validation of user input, may want some more testing ... but it seems to do the job of limiting input to a valid range ... well maximizing the range of numbers that can be converted ... limited only by the number of bits in an unsigned long.

It first prints out a table ... a table of max digits and max (string) value that can be obtained ... if limited by the intermediary use for storage in an unsigned long (commonly these days ... 32 bits)

// baseConversion_tinstaafl.cpp //

#include <iostream>
#include <iomanip>
#include <sstream>
#include <cctype> // re. toupper
#include <climits>

using namespace std;

typedef unsigned long UL;

const unsigned int NUM_BITS  = sizeof(UL) * 8;

const UL MAX_UL = ULONG_MAX;

// to track max values of other base numbers
// that fit into a UL ...
struct Values
{
    string max_value; // string max value
    unsigned int num_digits; // max num base digits that fit
} ;

// GLOBAL ARRAY!  Holds a TABLE of (above) Values ...
// to ease using index only in range of 1..36
Values TABLE[ 36+1 ]; // index 0 is NOT used here

const string REP = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";

// call this at BEGINNING of program ... to fill table
void fill( Values table[] );


string toBaseX( UL input, int nbase )
{
    ostringstream output;
    int digit = input % nbase;
    output << REP[digit];
    input /= nbase;
    while( input > 0 )
    {
        output.seekp(0);
        output << REP[input % nbase] << output.str();
        input /= nbase;
    }
    return output.str();
}
UL toBase10( const string& input, int base )
{
    int len = input.size();
    UL output = 0;
    for( int i = 0; i < len; ++i )
    {
        /* NOTE: input string *IS validataed* ALREADY */
        size_t pos = REP.find( toupper(input[i]) );
        output = output*base + pos;
    }
    return output;
}
string baseConverter( string num, int from, int to )
{
    return toBaseX( toBase10( num, from ), to );
}
string baseConverter( UL num, int from, int to )
{
    ostringstream oss;
    oss << num;
    return baseConverter( oss.str(), from, to );
}

// some utilities used here ...
std::string takeInString( const std::string& msg = "" )
{
    std::string val;
    std::cout << msg << std::flush;
    getline( std::cin, val );
    return val;
}
void toAllCaps( std::string& val )
{
    size_t len = val.size();
    while( len )
    {
        --len;
        val[len] = toupper( val[len] );
    }
}
int takeInChar( const std::string& msg = "" )
{
    std::string reply = takeInString( msg );
    if( reply.size() )
        return reply[0];
    // else ...
    return 0;
}
bool more()
{
    if( tolower( takeInChar( "More (y/n) ? " )) == 'n' )
        return false;
    // else ...
    return true;
}

int takeInInt( const string& msg, int max, int min = 0,
                const string& errMsg = "\nError!\n" )
{
    int val;
    while( true )
    {
        cout << msg << flush;
        if( cin >> val && cin.get() == '\n' && val <= max
                && val >= min )
            break;
        else
        {
            cout << errMsg;
            cin.clear();
            cin.sync();
        }
    }
    return val;
}
string leftPad( const string& inStr, unsigned int paddedLen )
{
    if( inStr.size() < paddedLen )
    {
        return string( (paddedLen - inStr.size()), '0' )
                + inStr;
    }
    // else ...
    return inStr;
}
bool isValid( const string& s, int base )
{

    if( !s.size() || s.size() > TABLE[base].num_digits )
    {
        cout << "\nMax digits allowed here = "
             << TABLE[base].num_digits
             << ", but you have entered " << s.size()
             << " digits.\n";
        return false;
    }

    string valid = REP.substr( 0, base );

    for( int i = s.size()-1; i >= 0; --i )
    {
        if( valid.find( toupper(s[i]) ) == string::npos )
        {
            cout << s[i] << " is NOT a valid char in '" << s
                 << "' ... Try again.\n"
                 << "Valid char's here are:  '"
                 << REP.substr( 0, base ) << "'\n";
            return false;
        }
    }

    if( leftPad( s, TABLE[base].num_digits ) >
                 TABLE[base].max_value )
    {
        cout << s << " exceeds max of "
             << TABLE[base].max_value << endl;
        return false;
    }

    // else ...
    return true;
}
/*
// convert string / return Number of type T ...
template < typename T >
T strToNum( const string& s )
{
    istringstream iss( s );
    T tmp;
    iss >> tmp;
    return tmp;
}
*/


int main()
{
    // TABLE is a Global array of struct of Values ... //
    fill( TABLE );

    for( int i = 2; i <= 36; ++i )
    {
        string tmp = TABLE[i].max_value;
        cout << "base " << setw(2) << i << ", "
             << setw(2) << TABLE[i].num_digits << ", "
             << baseConverter( tmp, i, 10 ) << ", "
             << tmp << endl;
    }

    string msg = "Enter the base for the number "
                 "to be converted:  ";
    string err = "\nTry again (valid range here is 2..36)\n";

    do
    {
        int base = takeInInt( msg, 36, 2, err );
        string numStr;
        do
        {
            cout << "Enter a number (base " << base
                 << "):  " << flush;
            getline( cin, numStr );
            toAllCaps( numStr );
        }
        while( !isValid( numStr, base ) );

        int nbase = takeInInt( "Enter the new base: ",
                                 36, 2, err );

        cout << numStr << " in base " << base
             << ", converted to base " << nbase << " is:\n";
        cout << baseConverter( numStr, base, nbase )
             << endl << endl;
    }
    while( more() );

    return 0;
}


// call this at BEGINNING of program ... to fill table
void fill( Values table[] )
{
    TABLE[0].num_digits = 0;
    TABLE[0].max_value = "";

    for( int base = 2; base <= 36; ++base )
    {
        string tmp = baseConverter( MAX_UL, 10, base );
        table[base].max_value = tmp;

        table[base].num_digits = tmp.size();
    }
}
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.