Start New Discussion within our Software Development Community

I'm new to Python, and as I was coding for Project Euler to develop my skills in this language, I needed a function for converting between two bases. I know that int() can convert anything to base 10, but before I looked for a Python module concerning this math, I thought it would be a good idea to try and code one myself. Please, let me know if there is anything inefficient or in bad style so that I can improve.

It can handle A-Z notation (input both lower- and uppercase), any bases between 2 and 36, and catches problems related in invalid bases.

Matt Laporte <> 2008
Base conversion tools. Allows for A-Z notation for digits greater than 9.
from types import StringType

def inBase(num, base, fromBase = 10, result = ''):
	Converts any number in fromBase to its representation in base.
	Defaults to converting to base_num from base_10.
	if result == '': 
		#First call checks and corrections.
                if num == 0: return '0' 
		base = __check(base)
		if fromBase != 10: 
			fromBase = __check(fromBase)
			""" In order to maintain the simplicity of the actual
			conversion, this converts the number to base_10. """
			num = toBase10(num, fromBase)
			fromBase = 10
		if num < 0: 
			#Further simplification for the conversion component.
			result = '-' + result
			num = -1 * num
	if num == 0: return result #Return the final result when num has been handled.
		#Conversion. This builds up result and eats away at num.
		thisDigit = num%base
		if thisDigit > 9: thisDigit = chr(thisDigit + 55) #Accounting for A-Z digits.
		else: thisDigit = str(thisDigit)
		return inBase(num/base, base, fromBase, thisDigit + result)
def __check(base):
	Verifies that a given base is 2-9 or A-Z.
	Converts any base from A-Z to 10-35 for numerical calculations.
	Should be used in the form: base == __check(base).
	if type(base) == StringType and ((ord(base) > 96) and (ord(base) < 123)):
		#Correct a-z to A-Z
		base = chr(ord(base)-32)
	if type(base) == StringType and ((ord(base) > 64) and (ord(base) < 91)):
		#Correct A-Z to 10-35
		return (ord(base) - 55)
	elif type(base) != type(1) or type(base) == StringType:
		#Not an integer, or any string other than A-Z.
		raise TypeError, 'invalid base type for inBase()'
	if base <= 1 or base > 36:
		raise ValueError, 'invalid base for inBase(): %s' % base
	return base

def toBase10(num, base):
	Converts any number represented in base to its base_10 representation.
	sum = 0
	parseNum = str(num)
	indices = range(len(parseNum)) #Exponents depend on digit place, indices necessary.
	for i in indices:
		#Add the decimal representations of the digits.
		sum += int(parseNum[i])*base**int(indices[::-1][i])
	return sum

p.s. I haven't found the Python standard library function for any of this yet. As well, having a little experience in C, C++, Java, etc, I can say that Python is amazing. This -- and I know to be careful -- mutability and interchangeability (that is heresy in C) makes everything so easy in Python.

Edit: I used timeit. Although toBase10 was an attempt to imitate int() for the purpose of experiment, it is 10-15 times slower, so using int() in place of toBase10: 1 million executions of inBase with fromBase = 10 took around 10 seconds, with fromBase != 10 took around 20. I think this is pretty bad...

As far as conversions are concerned there are a number of functions:

int(x [,base]) converts x to an integer
long(x [,base]) converts x to a long integer
float(x) converts x to a floating-point number
complex(real [,imag]) creates a complex number
chr(x) converts an integer to a character
unichr(x) converts an integer to a Unicode character
ord(c) converts a character to its integer value
hex(x) converts an integer to a hexadecimal string
oct(x) converts an integer to an octal string

Make sure you take note that int() and long() can take numbers of a different base, provided that you specify which base you are converting from, ie:

>>> int(0xAF)
>>> int('101',2)
>>> int('0xaf3', 16)

I would like to share this function that converts a number in base 10 to any base between 2 and 36. Originally it was limited to bases 2-16.

import string

def convDecToBase(num, base, dd=False):
    if not 2 <= base <= 36:
        raise ValueError, 'The base number must be between 2 and 36.'
    if not dd:
        dd = dict(zip(range(36), list(string.digits+string.ascii_lowercase)))
    if num == 0: return ''
    num, rem = divmod(num, base)
    return convDecToBase(num, base, dd)+dd[rem]

>>> convDecToBase(100000, 36)
>>> int('255s', 36)

Matt, Welcome to Python, and you're right about int(). No point reinventing the wheel!

If you are using Python3 ...

denary to any base (2 to 36) conversion

def den2anybase(number, radix):
    well, most any base with a radix in the range of 2 to 36
    given a denary integer number (base 10)
    return the base radix representation as a string
    # max base 36 can be represented by letters 0-9 and a-z
    abc = "0123456789abcdefghijklmnopqrstuvwxyz"
    if not 2 <= radix <= 36:
        # Python3 syntax
        raise ValueError("base radix must be from 2 to 36")
    result = []
    # negative number and zero
    if number < 0:
        number = -number
    elif number == 0:
        #return '0'
    while number:
        number, rdigit = divmod(number, radix)
    # reverse list of characters
    # join list characters to a string
    return ''.join(result)

# test the function
print(den2anybase(255, 16))   # ff
print(den2anybase(-255, 16))  # ff-
print(den2anybase(0, 16))     # 0


print(den2anybase(35, 36))    # z
print(den2anybase(6580, 36))  # 52s
print(den2anybase(255, 2))    # 11111111


# for base x to base y conversions
# use int(num_string, x) to get denary (base 10)
# then apply to den2anybase(denary, y)
# (remember base x and base y have a range of 2 to 36)
print(den2anybase(int('11111111', 2), 16))  # ff
print(den2anybase(int('52s', 36), 16))      # 19b4
print(int('19b4', 16))                      # 6580
This question has already been answered. Start a new discussion instead.