Skip to content

Instantly share code, notes, and snippets.

@JohannesMP
Last active September 14, 2022 02:14
Show Gist options
  • Save JohannesMP/a911b7dc02bb0586e3111a0cbd2dc0e2 to your computer and use it in GitHub Desktop.
Save JohannesMP/a911b7dc02bb0586e3111a0cbd2dc0e2 to your computer and use it in GitHub Desktop.
Converting a number from one base to another in C++
// NOTE: For the sake of practice, STL/stdlib helpers are not used, just std::string for memory management.
#include <string>
using std::string;
// Convert arbitrary base to base 10
// - Input must be valid number in the given base
// - Base must be between 2 and 36
// - If input or base are invalid, returns 0
long ConvertTo10(const string& input, int base)
{
if(base < 2 || base > 36)
return 0;
bool isNegative = (input[0] == '-');
int startIndex = input.length()-1;
int endIndex = isNegative ? 1 : 0;
long value = 0;
int digitValue = 1;
for(int i = startIndex; i >= endIndex; --i)
{
char c = input[i];
// Uppercase it - NOTE: could be done with std::toupper
if(c >= 'a' && c <= 'z')
c -= ('a' - 'A');
// Convert char to int value - NOTE: could be done with std::atoi
// 0-9
if(c >= '0' && c <= '9')
c -= '0';
// A-Z
else
c = c - 'A' + 10;
if(c >= base)
return 0;
// Get the base 10 value of this digit
value += c * digitValue;
// Each digit has value base^digit position - NOTE: this avoids pow
digitValue *= base;
}
if(isNegative)
value *= -1;
return value;
}
// Convert base 10 to arbitrary base
// - Base must be between 2 and 36
// - If base is invalid, returns "0"
// - NOTE: this whole function could be done with itoa
string ConvertFrom10(long value, int base)
{
if(base < 2 || base > 36)
return "0";
bool isNegative = (value < 0);
if(isNegative)
value *= -1;
// NOTE: it's probably possible to reserve string based on value
string output;
do
{
char digit = value % base;
// Convert to appropriate base character
// 0-9
if(digit < 10)
digit += '0';
// A-Z
else
digit = digit + 'A' - 10;
// Append digit to string (in reverse order)
output += digit;
value /= base;
} while (value > 0);
if(isNegative)
output += '-';
// Reverse the string - NOTE: could be done with std::reverse
int len = output.size() - 1;
for(int i = 0; i < len; ++i)
{
// Swap characters - NOTE: Could be done with std::swap
char temp = output[i];
output[i] = output[len-i];
output[len-i] = temp;
}
return output;
}
// Convert from one base to another
string ConvertBase(const string& input, int baseFrom, int baseTo)
{
// NOTE: There is probably a more efficient way to convert between two bases.
// This however is easy to understand and debug.
return ConvertFrom10(ConvertTo10(input, baseFrom), baseTo);
}
#include <iostream>
using std::cout;
using std::endl;
int main()
{
// Bases 10 and 2 (positive)
cout << "===== 1 =====" << endl;
cout << ConvertBase("101", 2, 10) << endl; // 100(2) = 5(10)
cout << ConvertBase("5", 10, 2) << endl; // 5(10) = 101(2)
// Bases 10 and 16 (negative)
cout << "===== 2 =====" << endl;
cout << ConvertBase("-1A", 16, 10) << endl; // -1A(16) = -26(10)
cout << ConvertBase("-26", 10, 16) << endl; // -26(10) = -1A(16)
// Bases 5 and 7
cout << "===== 3.1 =====" << endl;
cout << ConvertBase("100", 5, 10) << endl; // 100(5) = 25(10)
cout << ConvertBase("25", 10, 7) << endl; // 25(10) = 34(7)
// So therefore...
cout << "===== 3.2 =====" << endl;
cout << ConvertBase("100", 5, 7) << endl; // 100(5) = 34(7)
cout << ConvertBase("34", 7, 5) << endl; // 34(7) = 100(5)
// Larger Bases (26, 13)
cout << "===== 4 =====" << endl;
cout << ConvertBase("1234", 26, 13) << endl; // 1234(26) = 8864(13)
cout << ConvertBase("8864", 13, 26) << endl; // 8864(13) = 1234(26)
return 0;
}

To run embedded in a website, add the following html:

<script src="//onlinegdb.com/embed/js/ByP5zKVCZ"></script>
@samarth-bhargav
Copy link

samarth-bhargav commented May 5, 2020

The issue is in the reverse algorithm. Here is working code for anyone interested.
'

string ConvertFrom10(long value, int base)
{
if(base < 2 || base > 36)
return "0";

bool isNegative = (value < 0);
if(isNegative)
    value *= -1;

// NOTE: it's probably possible to reserve string based on value
string output;

do
{
    char digit = value % base;

    // Convert to appropriate base character
    // 0-9
    if(digit < 10)
        digit += '0';
        // A-Z
    else
        digit = digit + 'A' - 10;

    // Append digit to string (in reverse order)
    output += digit;

    value /= base;

} while (value > 0);

if(isNegative)
    output += '-';

// Reverse the string - NOTE: could be done with std::reverse
reverse(output.begin(), output.end());
return output;

}
'

@lec-Geisel
Copy link

lec-Geisel commented May 18, 2022

You should probably build the output string in reverse order. e.g. instead of:
output += digit;
try:
output = digit + output;

P.S.
You will also have to do the same for the sign.
output += '-';
Should be:
output = '-' + output;

@qdeanc
Copy link

qdeanc commented Sep 14, 2022

You should probably build the output string in reverse order. e.g. instead of: output += digit; try: output = digit + output;

P.S. You will also have to do the same for the sign. output += '-'; Should be: output = '-' + output;

I actually don't recommend doing this.

output = digit + output;
and even
output = output + digit;
Are both significantly slower operations than
output += digit;
when it comes to the std string data type.

Meanwhile, std:reverse is actually extremely performant.
So it's ultimately faster to build strings in reverse order using += and then reverse them using std::reverse.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment