# Python – Homework – Converting Any Base to Any Base

Posted on

### Question :

Python – Homework – Converting Any Base to Any Base

I’m trying to make a program to convert a number in any base to another base of the user’s choice. The code I have so far goes like this:

``````innitvar = float(raw_input("Please enter a number: "))
basevar = int(raw_input("Please enter the base that your number is in: "))
convertvar = int(raw_input("Please enter the base that you would like to convert to: "))
``````

These are the data that I get from the user. The initial number, its initial base, and the base the user wants to convert to. As I understand it, I need to convert to base 10, and then to the desired base, specified by the user.

This is where I’m hitting a brick wall: I need to multiply the leftmost digit in the initial number by its initial base, and then add the next digit to the right, and then repeat until I hit the rightmost digit. I understand how to do this on paper, but I have no idea how to put it into Python code. I’m not sure how I would multiply the first number, and then add the next, nor do I understand how to let the program know when to stop performing this operation.

I’m not asking to have the program written for me, but I would like to be pointed in the right direction.

This should be the first half of the answer to your problem. Can you figure out how to convert to a base?

``````# Create a symbol-to-value table.
SY2VA = {'0': 0,
'1': 1,
'2': 2,
'3': 3,
'4': 4,
'5': 5,
'6': 6,
'7': 7,
'8': 8,
'9': 9,
'A': 10,
'B': 11,
'C': 12,
'D': 13,
'E': 14,
'F': 15,
'G': 16,
'H': 17,
'I': 18,
'J': 19,
'K': 20,
'L': 21,
'M': 22,
'N': 23,
'O': 24,
'P': 25,
'Q': 26,
'R': 27,
'S': 28,
'T': 29,
'U': 30,
'V': 31,
'W': 32,
'X': 33,
'Y': 34,
'Z': 35,
'a': 36,
'b': 37,
'c': 38,
'd': 39,
'e': 40,
'f': 41,
'g': 42,
'h': 43,
'i': 44,
'j': 45,
'k': 46,
'l': 47,
'm': 48,
'n': 49,
'o': 50,
'p': 51,
'q': 52,
'r': 53,
's': 54,
't': 55,
'u': 56,
'v': 57,
'w': 58,
'x': 59,
'y': 60,
'z': 61,
'!': 62,
'"': 63,
'#': 64,
'\$': 65,
'%': 66,
'&': 67,
"'": 68,
'(': 69,
')': 70,
'*': 71,
'+': 72,
',': 73,
'-': 74,
'.': 75,
'/': 76,
':': 77,
';': 78,
'<': 79,
'=': 80,
'>': 81,
'?': 82,
'@': 83,
'[': 84,
'\': 85,
']': 86,
'^': 87,
'_': 88,
'`': 89,
'{': 90,
'|': 91,
'}': 92,
'~': 93}

# Take a string and base to convert to.
# Allocate space to store your number.
# For each character in your string:
#     Ensure character is in your table.
#     Find the value of your character.
#     Ensure value is within your base.
#     Self-multiply your number with the base.
# Return the number.

def str2int(string, base):
integer = 0
for character in string:
assert character in SY2VA, 'Found unknown character!'
value = SY2VA[character]
assert value < base, 'Found digit outside base!'
integer *= base
integer += value
return integer
``````

Here is the second half of the solution. By using these two functions, converting bases is very easy to do.

``````# Create a value-to-symbol table.
VA2SY = dict(map(reversed, SY2VA.items()))

# Take a integer and base to convert to.
# Create an array to store the digits in.
# While the integer is not zero:
#     Divide the integer by the base to:
#         (1) Find the "last" digit in your number (value).
#         (2) Store remaining number not "chopped" (integer).
#     Save the digit in your storage array.
# Return your joined digits after putting them in the right order.

def int2str(integer, base):
array = []
while integer:
integer, value = divmod(integer, base)
array.append(VA2SY[value])
return ''.join(reversed(array))
``````

After putting it all together, you should end up with the program below. Please take time to figure it out!

``````innitvar = raw_input("Please enter a number: ")
basevar = int(raw_input("Please enter the base that your number is in: "))
convertvar = int(raw_input("Please enter the base that you would like to convert to: "))

# Create a symbol-to-value table.
SY2VA = {'0': 0,
'1': 1,
'2': 2,
'3': 3,
'4': 4,
'5': 5,
'6': 6,
'7': 7,
'8': 8,
'9': 9,
'A': 10,
'B': 11,
'C': 12,
'D': 13,
'E': 14,
'F': 15,
'G': 16,
'H': 17,
'I': 18,
'J': 19,
'K': 20,
'L': 21,
'M': 22,
'N': 23,
'O': 24,
'P': 25,
'Q': 26,
'R': 27,
'S': 28,
'T': 29,
'U': 30,
'V': 31,
'W': 32,
'X': 33,
'Y': 34,
'Z': 35,
'a': 36,
'b': 37,
'c': 38,
'd': 39,
'e': 40,
'f': 41,
'g': 42,
'h': 43,
'i': 44,
'j': 45,
'k': 46,
'l': 47,
'm': 48,
'n': 49,
'o': 50,
'p': 51,
'q': 52,
'r': 53,
's': 54,
't': 55,
'u': 56,
'v': 57,
'w': 58,
'x': 59,
'y': 60,
'z': 61,
'!': 62,
'"': 63,
'#': 64,
'\$': 65,
'%': 66,
'&': 67,
"'": 68,
'(': 69,
')': 70,
'*': 71,
'+': 72,
',': 73,
'-': 74,
'.': 75,
'/': 76,
':': 77,
';': 78,
'<': 79,
'=': 80,
'>': 81,
'?': 82,
'@': 83,
'[': 84,
'\': 85,
']': 86,
'^': 87,
'_': 88,
'`': 89,
'{': 90,
'|': 91,
'}': 92,
'~': 93}

# Take a string and base to convert to.
# Allocate space to store your number.
# For each character in your string:
#     Ensure character is in your table.
#     Find the value of your character.
#     Ensure value is within your base.
#     Self-multiply your number with the base.
# Return the number.

integer = 0
for character in innitvar:
assert character in SY2VA, 'Found unknown character!'
value = SY2VA[character]
assert value < basevar, 'Found digit outside base!'
integer *= basevar
integer += value

# Create a value-to-symbol table.
VA2SY = dict(map(reversed, SY2VA.items()))

# Take a integer and base to convert to.
# Create an array to store the digits in.
# While the integer is not zero:
#     Divide the integer by the base to:
#         (1) Find the "last" digit in your number (value).
#         (2) Store remaining number not "chopped" (integer).
#     Save the digit in your storage array.
# Return your joined digits after putting them in the right order.

array = []
while integer:
integer, value = divmod(integer, convertvar)
array.append(VA2SY[value])

# Display the results of the calculations.
``````

I need to multiply the leftmost digit in the initial number by its innitial base, and then add the next digit to the right, and then repeat until I hit the rightmost digit.

So you need to get digits. In a list.

Hint 1: Use `divmod()` function to break a number into digits. Divide by 10 to get decimal digits.

Hint 2: While n > 0: you can use `divmod()` to get a quotient and a remainder. If you save the remainder in the list, and use the quotient as the new value of n your number gets smaller until what’s left is zero and you’re done.

Hint 3: Your digits arrive in right-to-left order. Use `reverse` to switch the order of the list of this bothers you. Or create the list by using `insert(0,digit)`.

Now that you have the digits. In a list. You can iterate through the list.

Try the `for` statement on for size.

You might need to use a “multiple and add” loop. `total = total * new_base + next_digit` is the way the body of the loop often looks.

Just a Student, slow down with the idea of what you need. You may not need what you think you need.

Start at the beginning: the user inputs a number. The user inputs a base. These are both Strings. Say the base is 12, and the number is 1AB3. So you have a ‘1’ in the 12^3 place, an ‘A’ in the 12^2 place, a ‘B’ in 12^1, and a ‘3’ in the 12^0 (ones) place. If you want this number in base 10, you’re going to need to add some numbers together.

Specifically, you need to add 1*12^3 + 10*12^2 + 11*12^1 + 3*12^0. Notice something here: you have 3,2,1,0. Which corresponds nicely to the LENGTH of the input string 1AB3. So probably a `for` loop would be helpful here. The user doesn’t input an integer, they input a string. So you need the characters from the string, not the digits from the number.

How do you know what the symbols ‘A’ and ‘C’ represent in decimal notation? Look at the answer from Noctis Skytower!

So your first task is to figure out how to ITERATE THROUGH A STRING. Your second task is to figure out how to use the individual character values from your string to access the dictionary in Noctis Skytower’s answer, and your third task is to figure out how to write a loop that takes advantage of that information.

You need to write two functions. In Scheme (since I know Scheme much better than Python :-P), those two functions are called `string->number` and `number->string`, though of course you can name them whatever you like.

Each of those functions needs to take a base parameter to do the conversion in. You can make it default to 10, if you like.

Once you implement each of those successfully, the rest is a piece of cake.

Test cases for you:

``````assert str2num('1234', 10) == 1234
assert str2num('1234', 16) == 0x1234
assert num2str(1234, 10) == '1234'
assert num2str(1234, 16) == '4d2'
assert num2str(0x1234, 16) == '1234'
``````

`int()` can convert strings from any base between 2 and 36. If you need a wider range than that then create a string containing the digits and use the `index()` method to get the value.

I came here looking for shortcuts but looks like none exist. So here are the long methods I have found.

The easiest way(probably) is to convert any number from a base b1 to b2 is to convert b1?Decimal?b2.

A number in the base b1 can be treated like a polynomial in the base b1,

ie, a 4-digit number abcd = d*(b1^0)+c*(b1^1)+b*(b1^2)+a*(b1^3)

Eg., 123(Decimal) = 3*(10^0)+2*(10^1)+1*(10^2)

So, to convert from any base to Decimal, find the sum of all `[digit*(base^power)]` (where power is 0 to [NumOfDigits-1]) in the reverse order of the digits.
For this, treat the number as a `string` and iterate through it using a `for` loop.

So, the input should be a `string` and the op an `int`.

The next step is to convert a Decimal number D to base b2.

Divide D/b2, the remainder is the rightmost digit.
Divide the quotient by b2, the remainder this time is the next rightmost digit.
Repeat this cycle until the quotient is 0.

Eg.,

8(Dec) to Binary:

8/2=4; 8%2=0

4/2=2; 4%2=0

2/2=1; 2%2=0

1/2=0; 1%2=1

8(Dec)=1000(Bin)

This is done by treating the output number as a string, and reversing the string after concatenating all the digits to it. (See above: `'0' + '0' + '0' + '1' ='0001'` , reverse it ? ‘1000’

For these two processes, the following python program would do:

``````    N=input("Num:")
B1=int(input("FromBase:"))
B2=int(input("ToBase:"))
print("Base[",B1,"]:",N)

#From Base B1 to Decimal
DN=0
for i in range(len(N)):
DN+= int(N[::-1][i]) * (B1 ** i)
print("Decimal:",DN)

#From Decimal to Base B2
if int(N) == 0:
BN = 0
else:
BN = ""
while DN > 0:
BN += str(DN % B2)
DN = int(DN / B2)
print("Base[",B2,"]:",int(BN[::-1]))
``````

But you’ll notice that this program is not practical while using bases more than 10.
For this purpose, you need to use more digits to represent values more than 0-9. For that you will have to use long `if-else` ladders to select the digits according the face value or vise versa.

``````N=input("Num:")
B1=int(input("FromBase:"))
B2=int(input("ToBase:"))
print("Base[",B1,"]:",N)

#From Base B1 to Decimal
DN=0
for i in range(len(N)):
if N[::-1][i] == '0':
DN += 0 * (B1 ** i)
elif N[::-1][i] == '1':
DN += 1 * (B1 ** i)
elif N[::-1][i] == '2':
DN += 2 * (B1 ** i)
'''    :
:       '''
elif N[::-1][i] == 'A':
DN += 10 * (B1 ** i)
'''    :
:  (fill it) ....
:       '''
print("Decimal:",DN)

#From Decimal to Base B2
if int(N) == 0:
BN = 0
else:
BN = ""
while DN > 0:
R = DN % B2
if R==0:
BN += '0'
elif R==1:
BN += '1'
elif R==2:
BN += '2'
'''     :
:
:       '''
elif R==10:
BN += 'A'
'''     :
:
:       '''
DN = int(DN / B2)
print("Base[",B2,"]:",int(BN[::-1]))
``````

Almost everyone avoids this long `if-else` ladder by using a dictionary with the face values as keys and the symbols/digits as their respective values.
Now the program becomes:

``````Dig={0: '0', 1: '1', 2: '2', 3: '3', 4: '4', 5: '5', 6: '6', 7: '7', 8: '8', 9: '9', 10: 'A', 11: 'B', 12: 'C', 13: 'D', 14: 'E', 15: 'F', 16: 'G', 17: 'H', 18: 'I', 19: 'J'}

N=input("Num:")
B1=int(input("FromBase:"))
B2=int(input("ToBase:"))
print("Base[",B1,"]:",N)

#From Base B1 to Decimal
DN=0
for i in range(len(N)):
for fv in Dig:
if Dig[fv]== N[::-1][i]:    # FaceValue of the Digit
DN+= fv * (B1 ** i)
print("Decimal:",DN)

#From Decimal to Base B2
if N == '0':
BN = 0
else:
BN = ""
while DN > 0:
BN += Dig[DN % B2]          # Digit for the Value
DN = int(DN / B2)
print("Base[",B2,"]:",BN[::-1])
``````

?There’s? your homework. Select any on of those? three methods.

To use even more bases, you can just expand the dictionary and create a long one like @Noctis Skytower.

Every single website I checked had long dictionaries like that, but I tend to use shortcuts for almost everything. I used simple `range()` function, `if-else` statements, and simple `for` loops to shorten the process(but I think it looks a bit confusing, despite being simple).
The advantage of this is that it’s very easy to add more bases by just adding a key, `range(a,b)`, for the range of face values of digits, and a value, `range(x,y)`, for the range of Unicode values of the characters for the respective values.

``````Val = {range(10):range(48, 58), range(10,36): range(65, 91)}

N=input("Num:")
B1=int(input("FromBase:"))
B2=int(input("ToBase:"))
print("Base[",B1,"]:",N)

#From Base B1 to Decimal
DN = 0
for i in range(len(N)):
for j in Val:
if ord(N[i]) in Val[j]:
FV=j[ord(N[i])-Val[j]]       # FaceValue of the Digit
if FV>= B1:                             # Digits aren't >=Base, right?
print("Base Error..")
exit()
else:
DN += FV * (B1 ** (len(N) - 1 - i))
print("Decimal:",DN)

#From Decimal to Base B2
if int(DN) == 0:
BN = '0'
else:
BN = ""
while DN > 0:
R = DN % B2
for i in Val:
if R in i:
BN+=chr(Val[i][R-i])     #Finding the Digit for the Value
DN = int(DN / B2)
print("Base[", B2, "]:", BN[::-1])
``````

This can also be done using functions:

``````Val = {range(10):range(48, 58), range(10,36): range(65, 91)}

def B2D(N,B1):
'''From Base B1 to Decimal'''
DN = 0
for i in range(len(N)):
for j in Val:
if ord(N[i]) in Val[j]:
FV=j[ord(N[i])-Val[j]]       # FaceValue of the Digit
if FV>= B1:                             # Digits aren't >=Base, right?
print("Base Error..")
exit()
else:
DN += FV * (B1 ** (len(N) - 1 - i))
return DN

def D2B(DN,B2):
'''From Decimal to Base B2'''
if int(DN) == 0:
BN = '0'
else:
BN = ""
while DN > 0:
R = DN % B2
for i in Val:
if R in i:
BN+=chr(Val[i][R-i])     #Finding the Digit for the Value
DN = int(DN / B2)
return BN[::-1]

def B2B(N,B1,B2):
return D2B(B2D(N,B1),B2)

N=input("Num:")
B1=int(input("FromBase:"))
B2=int(input("ToBase:"))
print("Base[",B1,"]:",N)
print("Decimal:",B2D(N,B1))
print("Base[",B2,"]:",B2B(N,B1,B2))
``````

Now, if you can expand the dictionary, you can probably convert from any base to any base. ?

These are some shortcuts I found on other StackOverflow Q-A and other websites:

To convert nums from any base between 2 & 36 to Decimal: `int(‘NumberString’,Base)`

``````>>> int('1000',2)
8
>>> int('100',12)
144
>>> int('AA',17)
180
>>> int('Z',36)
35
>>> int('Z',37)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: int() base must be >= 2 and <= 36, or 0
``````

To convert Decimal into Binary, Octal, and Hex:

``````>>> bin(8)
'0b1000'
>>> oct(8)
'0o10'
>>> hex(8)
'0x8'
``````

Hope this `TL;DR` helped someone. If somebody can point out any mistakes, edit this, or provide shorter methods, I’ll be grateful.

Its easy.
First, I made a `number.py`

``````class number:
def __init__(self, value: str, base):
alphabet = [str(i) for i in range(10)] + [chr(i).upper() for i in range(97, 123)]
self.val = [c for c in value]
self.alph = alphabet[:base]
self.last = self.alph[-1]
self.first = self.alph
self.len_alph = len(alphabet)

def last_that_is_not(self,number, target):
for idx, c in enumerate(number[::-1]):
if c != target: return len(number)-1 - idx
return

def next(self):
# We look for the last letter that isn't equal to self.last
change_loc = self.last_that_is_not(self.val, self.last)
if change_loc is not None:
elem = self.val[change_loc]
new_letter = self.alph[self.alph.index(elem)+1]
self.val[change_loc] = new_letter
len_val = len(self.val)
# In case last that is not isnt the last letter
change_loc = -1 if change_loc is None else change_loc
increment = change_loc == -1
for idx in range(change_loc+1, len_val):
self.val[idx] = self.alph
if increment:
self.val = [self.alph] + [self.alph for i in range(len_val)]

def prev(self):
# we look for the last letter that isn't equal to self.first
change_loc = self.last_that_is_not(self.val, self.first)
if change_loc is not None:
elem = self.val[change_loc]
new_letter = self.alph[self.alph.index(elem)-1]
self.val[change_loc] = new_letter
len_val = len(self.val)
# In case last that is not is first letter
self.val = [alphabet[-1] for i in range(len_val - 1)]

def __repr__(self):
return ''.join(self.val)
__str__ = __repr__

``````

then `main.py`

``````#!/usr/bin/pypy3
from time import time
from math import log, ceil
from number import number as num_baseX

# converts a number from base base to base 10
def convert2int(number, base = 10):
number = number.upper()
result = 0
l = int(base**(len(number) - 1))
for n in number:
if '0' <= n <= '9':
result += l*(ord(n) - ord('0'))
else:
result += l*(ord(n) - 55)
# ord('A') - 10 = 55
l = round(l/base)
return result

# convertit un nombre de base 10 en
# un nombre de base base, base <= 36
def base10toX(number: int, base=10):
start = ''.join(['0' for _ in range(ceil(log(number, base)))])
start = '0'
result = num_baseX(start, base)
def _wrapper(number: int, base = 10):
nonlocal result
log_num = int(log(number, base))
for i in range(base**log_num):
result.next()
number = number - base**log_num
if number > 0:
_wrapper(number, base)
_wrapper(number, base)
return result

def baseXtoY(**kwargs):
"""
Usage:
baseXtoY(num, X, Y)
num = number
X = base of num
Y = base to convert to
"""
integer_num = convert2int(kwargs['num'], kwargs['X'])
return base10toX(integer_num, kwargs['Y'])
``````

NOTE: I, L. Pham-Trong wrote this code. It is protected by the 4-close BSD licence :

``````Copyright (c) 2021, Luca PHAM-TRONG

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.

3. All advertising materials mentioning features or use of this software must
display the following acknowledgement:
This product includes software developed by L. Pham-Trong, and this guy rocks.

4. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY COPYRIGHT HOLDER "AS IS" AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
EVENT SHALL COPYRIGHT HOLDER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
``````