Welcome, guest | Sign In | My Account | Store | Cart

This function takes in any base-10 integer and returns the string representation of that number in its specified base-n form.

Up to base-36 is supported without special notation for symbolizing when a number is really in a single digit position. When that does occur, the number that takes up that single base is surrounded by parantheses.

[2004-06-30: Renamed function to base10toN to be more proper]

[2001-06-17: Changed comments to base-36 instead of base-35; thanks Klaus Alexander Seistrup]

[2001-06-17: Added for loop mechanism in Discussion for alternative way of creating num_rep dictionary; thanks Hamish Lawson for suggesting that possibility]

Python, 42 lines
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
def base10toN(num,n):
    """Change a  to a base-n number.
    Up to base-36 is supported without special notation."""
    num_rep={10:'a',
         11:'b',
         12:'c',
         13:'d',
         14:'e',
         15:'f',
         16:'g',
         17:'h',
         18:'i',
         19:'j',
         20:'k',
         21:'l',
         22:'m',
         23:'n',
         24:'o',
         25:'p',
         26:'q',
         27:'r',
         28:'s',
         29:'t',
         30:'u',
         31:'v',
         32:'w',
         33:'x',
         34:'y',
         35:'z'}
    new_num_string=''
    current=num
    while current!=0:
        remainder=current%n
        if 36>remainder>9:
            remainder_string=num_rep[remainder]
        elif remainder>=36:
            remainder_string='('+str(remainder)+')'
        else:
            remainder_string=str(remainder)
        new_num_string=remainder_string+new_num_string
        current=current/n
    return new_num_string

The main use for this function is to be able to easily know what a number looks like in binary, octal, and hexidecimal; binary especially. It is very useful for when you are dealing with bitwise operations and you want to know what the actual bits for a number look like.

As suggested by Hamish Lawson, the num_rep dictionary could be done using a for loop if you prefer:

starting_num=10 num_rep={} for letter in string.lowercase: num_rep[starting_num]=letter starting_num+=1

I have chosen to leave it as-is since the above has a very slight performance hit from the for loop and the way I have it in the code is more verbose.

18 comments

Klaus Alexander Seistrup 22 years, 9 months ago  # | flag

Max is base-36. Just as 9 is the biggest number in base-10, z is the biggest number in base-36, not base-35.

Hamish Lawson 22 years, 9 months ago  # | flag

Setting up num_rep more concisely? Couldn't the num_rep dictionary be more concisely set up using a for loop (assuming you want to stick to doing the conversion using dictionary lookup rather than computation)?

Martin v. Löwis 21 years, 2 months ago  # | flag

Input is not decimal. The description of the algorithm is incorrect: it does not take a decimal number as input, but a Python integer object - whether this was created through a decimal literal, or through a hexadecimal one, or through some other expression is irrelevant.

Greg Jorgensen 19 years, 8 months ago  # | flag

quite a few problems, and not a great implementation. This code fails in several ways:

  • base = 1 causes infinite loop

  • base = 0 causes divide by zero

  • non-numerics passed for number or base cause exception

  • incorrectly converts number 0 to "" for any base

The code is much longer than it should be. Using a dictionary for a sequentially-indexed list of letters is wasteful; even worse is the suggestion to populate the dictionary with a for loop. Making the distinction between digits in the 0..9 range and digits in the a..z range over-complicates the code. The digits needed for bases 2..36 are a constant string.

Here's a version that doesn't have these problems (though it may have other bugs). And I think it is more Pythonic.

def baseconvert(n, base):
    """convert positive decimal integer n to equivalent in another base (2-36)"""

    digits = "0123456789abcdefghijklmnopqrstuvwxyz"

    try:
        n = int(n)
        base = int(base)
    except:
        return ""

    if n < 0 or base < 2 or base > 36:
        return ""

    s = ""
    while 1:
        r = n % base
        s = digits[r] + s
        n = n / base
        if n == 0:
            break

    return s

It doesn't deal with base > 36 but it should be obvious how to extend the code to do it.

Greg Jorgensen

PDXperts LLC - Portland, Oregon USA

Aloysio Figueiredo 16 years, 5 months ago  # | flag
def base10toN(num,n):
   return ((num == 0) and  "0" ) or ( base10toN(num // n, n).strip("0") + "0123456789abcdefghijklmnopqrstuvwxyz"[:n][num % n])

:)

Aloysio Figueiredo 16 years, 5 months ago  # | flag

Or to put it really short:

def base10toN(num,n):
   return ((num == 0) and  "0" ) or ( base10toN(num // n, n).strip("0") + "0123456789abcdefghijklmnopqrstuvwxyz"[:n][num % n])

:)

Kip Bryan 16 years ago  # | flag

Aloysio's short, but fixed. Thanks Aloysio for the inspiring one-liner version. However it didn't work for numbers that end in zero, such as 4 in base 2, which should be 100 but it gives 10. Here's an adjusted one. Note that none of these are converting from "base 10" as integers are stored in binary, normally. This also omits the [:n] substring from the original.

def baseN(num,b):
  return ((num == 0) and  "0" ) or ( baseN(num // b, b).lstrip("0") + "0123456789abcdefghijklmnopqrstuvwxyz"[num % b])
trottier 15 years, 1 month ago  # | flag

Made more generic and pythonic still:

def baseN(num,b,numerals="0123456789abcdefghijklmnopqrstuvwxyz"):
    return ((num == 0) and  "0" ) or ( baseN(num // b, b).lstrip("0") + numerals[num % b])
wanyewon 14 years, 7 months ago  # | flag

The previous versions had a few bugs: They didn't pass the numerals to the recursion call so you could only use different numerals for small numbers. Crazy cases like negative numbers and base 1 caused infinite recursions. The readability was that of an ancient Egyptian scroll.

Here's my take on this:

def baseN(num, base, numerals="0123456789abcdefghijklmnopqrstuvwxyz"):
    """
    Convert any int to base/radix 2-36 string. Special numerals can be used
    to convert to any base or radix you need. This function is essentially
    an inverse int(s, base).

    For example:
    >>> baseN(-13, 4)
    '-31'
    >>> baseN(91321, 2)
    '10110010010111001'
    >>> baseN(791321, 36)
    'gyl5'
    >>> baseN(91321, 2, 'ab')
    'babbaabaababbbaab'
    """
    if num == 0:
        return "0"

    if num < 0:
        return '-' + baseN((-1) * num, base, numerals)

    if not 2 <= base <= len(numerals):
        raise ValueError('Base must be between 2-%d' % len(numerals))

    left_digits = num // base
    if left_digits == 0:
        return numerals[num % base]
    else:
        return baseN(left_digits, base, numerals) + numerals[num % base]
sebastianjb 13 years, 7 months ago  # | flag

I may as well throw in my version. I find it simpler without recursion:

def str_base(num, base, numerals = '0123456789abcdefghijklmnopqrstuvwxyz'):
    if base < 2 or base > len(numerals):
        raise ValueError("str_base: base must be between 2 and %i" % len(numerals))

    if num == 0:
        return '0'

    if num < 0:
        sign = '-'
        num = -num
    else:
        sign = ''

    result = ''
    while num:
        result = numerals[num % (base)] + result
        num //= base

    return sign + result
Shashwat Anand 13 years ago  # | flag

Well, here is my version.

def base10toN(num, base):
    """Change ``num'' to given base
    Upto base 36 is supported."""

    converted_string, modstring = "", ""
    currentnum = num
    if not 1 < base < 37:
        raise ValueError("base must be between 2 and 36")
    if not num:
        return '0'
    while currentnum:
        mod = currentnum % base
        currentnum = currentnum // base
        converted_string = chr(48 + mod + 7*(mod > 10)) + converted_string
    return converted_string
Shashwat Anand 13 years ago  # | flag

@Brett: Your recipe is Wrong for one particular case. It fails for num = 0. The answer should be '0' and not a blank string. The issue is with:

new_num_string=''
current=num
while current!=0:
    # Foobar
return new_num_string

Now if num = 0, it never goes into while loop and returns new_num_string which is "".

Jonathan Hartley 12 years, 8 months ago  # | flag

Hey. I've never really been to ActiveState before, so I might be tripping over cultural norms here, but why are people posting competing snippets of code without any test cases? Seems like anyone coming to this page has to evaluate every snippet in turn until they find one that actually works, rather than simply being able to see at a glance 'passes all the tests' or 'doesnt'.

Marko Kukovec 10 years, 6 months ago  # | flag

Here is another solution:

'''
Created on 20. sep. 2013

@author: Kukovec
'''

def __DecimalToAnyBaseArrayRecur__(array, decimal, base):
    array.append(decimal % base)
    div = decimal / base
    if(div == 0):
        return;
    __DecimalToAnyBaseArrayRecur__(array, div, base)

def DecimalToAnyBaseArray(decimal, base):
    array = []
    __DecimalToAnyBaseArrayRecur__(array, decimal, base)
    return array[::-1]

def Test():
    print DecimalToAnyBaseArray(1258, 16)
    print DecimalToAnyBaseArray(1258, 10)
    print DecimalToAnyBaseArray(1258, 8)
    print DecimalToAnyBaseArray(1258, 2)

if __name__ == "__main__":
    Test()

Output:

[4, 14, 10]
[1, 2, 5, 8]
[2, 3, 5, 2]
[1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0]
mukundan 9 years, 5 months ago  # | flag

def base(decimal ,base) : list = "0123456789ABCDEFGHIJKLMOPQRSTUVWXYZ" answer = "" while decimal != 0 : answer += list[decimal % base] decimal /= base return answer[::-1] print base(100,8)

mukundan 9 years, 5 months ago  # | flag

here is a another solution:

def base(decimal ,base) :
    list = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    answer = ""
    while decimal != 0 :
        answer  += list[decimal % base]
        decimal /= base
    return answer[::-1]

print base(35,36)

output:

Z
Pier 8 years, 3 months ago  # | flag

I have expanded on mukundan's function to implement fraction base conversion capabilities.

def base(decimal,base) :
"""
expand mukundan's function adding capability to convert fractions,
from http://www.cut-the-knot.org/blue/frac_conv.shtml
"""
    list = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    int_dec=int(decimal)
    frac_dec=decimal-int(decimal)
    int_result = ""
    frac_result = ""
    while int_dec != 0 :
        int_result  += list[int_dec % base]
        int_dec /= base
    while frac_dec != 0 :
        frac_result += list[int(frac_dec*base)]
        frac_dec = frac_dec*base - int(frac_dec*base)
    return int_result[::-1] + "." + frac_result[::1]
Tibor Tajti 6 years, 10 months ago  # | flag

Yet shorter version:

def tobaseN(n,N,D="0123456789abcdefghijklmnopqrstuvwxyz"):
    return (tobaseN(n//N,N)+D[n%N]).lstrip("0") if n>0 else "0"
Created by Brett Cannon on Thu, 14 Jun 2001 (PSF)
Python recipes (4591)
Brett Cannon's recipes (16)

Required Modules

  • (none specified)

Other Information and Tasks