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 <lapo3399@gmail.com> 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.
	else:
		#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...

Recommended Answers

All 4 Replies

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)
175
>>> int('101',2)
5
>>> int('0xaf3', 16)
2803
>>>

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]

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

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

If you are using Python3 ...

''' den2anybase.py
denary to any base (2 to 36) conversion
Python3
'''

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
        result.append('-')
    elif number == 0:
        #return '0'
        result.append('0')
    while number:
        number, rdigit = divmod(number, radix)
        result.append(abc[rdigit])
    # reverse list of characters
    result.reverse()
    # 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('-'*20)

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

print('-'*20)

# 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
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.