Search code examples
c++arraysnumber-systems

How to switch from hexadecimal to 2^16 system in c++


I have a task like this: The user enters the numbers N1(str1) and N2(str2) in hexadecimal. The program must convert the numbers from hexadecimal to a system of 2 ^ 16 and count the sum of the numbers N1 and N2 in the 2^16 system, then translate the result into a hexadecimal system.

I had such an idea: first convert from hexadecimal to decimal (I can do this). Then take each number modulo 2 ^ 16 the logarithm of the base 2 ^ 16 of the number N1dec(dec11) (or N2dec(dec22)) times and write the remainders in the corresponding arrays. This is where my problems began. My conversion from decimal to 2^16 system does not work. Hope You can help.

#include <iostream> 
using namespace std;

int main()
{
//HEX to decimal
const char* const str1 = "101D0";//7A120 = 500000; 101D0 = 66000;   //1F4 = 500=dec1=N1
cout << "Hello!\nFirst number in HEX system is " << str1 << endl;
istringstream is(str1);
int dec1;
is >> hex >> dec1;
if (!is && !is.eof()) throw "dammit!";
cout << "First number in decimal system: " << dec1 << endl;
const char* const str2 = "1567";//5479=dec2=num2
cout << "Second number in HEX system is " << str2 << endl;
istringstream iss(str2);
int dec2;
iss >> hex >> dec2;
if (!iss && !iss.eof()) throw "dammit!";
cout << "Second number in decimal system: " << dec2 << endl;
//

//Decimal to 2^16 system
int dec11 = dec1;//because dec11 will be = 0
int dec22 = dec2;//because dec22 will be = 0

int k = 1 << 16;
cout << "2^16 = " << k << endl;
int intPART1 = log(dec11) / log(k);
cout << "Int part of log2^16 (" << dec11 << ") is " << intPART1 << endl << "So num1 in 2^16 system will look like ";

int *n1 = new int[intPART1 + 1];
for (int i = 0; i <= intPART1; i++)
{
    if (i != 0)
    {
        n1[i] = dec11 % k*(1<<16-1);
        dec11 = dec11 / k;
    }
    else
    {
        n1[i] = dec11 % k;
        dec11 = dec11 / k;
    }
}
for (int i = intPART1; i >= 0; i--)
{
    cout << n1[i] << "   ";
}
cout << endl;
int intPART2 = log(dec22) / log(k);
cout << "Int part of log2^16 (" << dec22 << ") is " << intPART2 << endl << "So num2 in 2^16 system will look like ";

int *n2 = new int[intPART2 + 1];
for (int i = 0; i <= intPART2; i++)
{
    if (i != 0)
    {
        n2[i] = dec22 % k*(1 << 16 - 1);
        dec22 = dec22 / k;
    }
    else
    {
        n2[i] = dec22 % k;
        dec22 = dec22 / k;
    }
}

for (int i = intPART2; i >= 0; i--)
{
    cout << n2[i] << "   ";
}
cout << endl;

Solution

  • Since hexadecimal values are of base 16, let us say 16^1 and base 2^16 can be recalculated to 16^4 we can already see that your target base is a multiple of your source base. This makes the computation pretty easy and straight forward. All we have to do is some bit shifiting.

    int hexToInt(char c)
    {
        if (c >= 'a')
            return c - 'a' + 10;
        if (c >= 'A')
            return c - 'A' + 10;
        return c - '0';
    }
    
    // Converts hex to base 2^16. vector[0] holds the MSB.
    std::vector<unsigned short> toBase0x10000(std::string const& hex)
    {
        std::size_t bufSize = hex.size() / 4 + (hex.size() % 4 > 0);
        std::vector<unsigned short> number(bufSize);
    
        int shift = 0;
        int value = 0;
        std::size_t numIndex = number.size();
    
        for (int i = hex.size() - 1; i >= 0; i--)
        {
            value |= hexToInt(hex[i]) << shift;
            shift += 4;
    
            if (shift == 16)
            {            
                number[--numIndex] = static_cast<unsigned short>(value);
                shift = 0;
                value = 0;
            }
        }
    
        if (value != 0)
            number[--numIndex] = static_cast<unsigned short>(value);
    
        return number;
    }
    
    std::string fromBase0x10000(std::vector<unsigned short> const& num)
    {
        std::stringstream ss;
        for (auto&& digit : num)
            ss << std::hex << digit;
        return ss.str();
    }
    

    toBase0x10000 returns a std::vector<unsigned short> so each element in the vector represents one digit of your base 2^16 number (since unsigned short can hold exaclty that value range).

    As a side effect this implementation supports any precision number so you are not limited by the value range of numeric types like int or long.

    Here is a full example.