320

Python allows easy creation of an integer from a string of a given base via

int(str, base). 

I want to perform the inverse: creation of a string from an integer, i.e. I want some function int2base(num, base), such that:

int(int2base(x, b), b) == x

The function name/argument order is unimportant.

For any number x and base b that int() will accept.

This is an easy function to write: in fact it's easier than describing it in this question. However, I feel like I must be missing something.

I know about the functions bin, oct, hex, but I cannot use them for a few reasons:

  • Those functions are not available on older versions of Python, with which I need compatibility with (2.2)

  • I want a general solution that can be called the same way for different bases

  • I want to allow bases other than 2, 8, 16

Related

wjandrea
  • 28,235
  • 9
  • 60
  • 81
Mark Borgerding
  • 8,117
  • 4
  • 30
  • 51
  • 7
    Surprisingly no one gave a solution which works with arbitrary big base (1023). If you need it, check my solution which works for every base (2 to inf) http://stackoverflow.com/a/28666223/1090562 – Salvador Dali Feb 23 '15 at 02:55
  • I have incorporated the solution with arbitrary big bases into my code as standard for bases larger 62 and provided also reverse conversion in the same function. So if there is anyone interested, just check it out: https://stackoverflow.com/a/71027453/7711283 . – Claudio Feb 08 '22 at 01:26
  • Hi, there exists a library called Basencode for this problem, please check out [my answer](https://stackoverflow.com/a/74324587/13981530). Hope it helps! – Safwan Samsudeen Nov 05 '22 at 02:59

35 Answers35

216

Surprisingly, people were giving only solutions that convert to small bases (smaller than the length of the English alphabet). There was no attempt to give a solution which converts to any arbitrary base from 2 to infinity.

So here is a super simple solution:

def numberToBase(n, b):
    if n == 0:
        return [0]
    digits = []
    while n:
        digits.append(int(n % b))
        n //= b
    return digits[::-1]

so if you need to convert some super huge number to the base 577,

numberToBase(67854 ** 15 - 102, 577), will give you a correct solution: [4, 473, 131, 96, 431, 285, 524, 486, 28, 23, 16, 82, 292, 538, 149, 25, 41, 483, 100, 517, 131, 28, 0, 435, 197, 264, 455],

Which you can later convert to any base you want

  1. at some point of time you will notice that sometimes there is no built-in library function to do things that you want, so you need to write your own. If you disagree, post you own solution with a built-in function which can convert a base 10 number to base 577.
  2. this is due to lack of understanding what a number in some base means.
  3. I encourage you to think for a little bit why base in your method works only for n <= 36. Once you are done, it will be obvious why my function returns a list and has the signature it has.
Trenton McKinney
  • 56,955
  • 33
  • 144
  • 158
Salvador Dali
  • 214,103
  • 147
  • 703
  • 753
  • Excellent answer! Good thinking leaving the number in a list; it makes it easier to come up with one's own character representation of numbers in different bases. – Sylvester Kruin May 13 '22 at 17:12
  • How would you then convert that list into a single character representation, if you had for example a string of characters like 0-9 plus A-Z plus 541 extra unicode characters? `s = "0123456789ABCDEF"` `n = [15,1,13]` `"".join([s[x] for x in n])` – PhilHibbs Jun 17 '22 at 10:24
  • @PhilHibbs Sure, that way works. Of course, you have to decide which symbols to use and in what order. – Karl Knechtel Aug 31 '22 at 09:46
  • You can extend your answer to include base 1. `if b == 1: return n * [1]` – Jeff Oct 30 '22 at 21:32
  • Hi, a reply to point 1 - we do have a library for this, please check out [my answer](https://stackoverflow.com/a/74324587/13981530). +1 for your valuable answer - my answer just adds to yours! – Safwan Samsudeen Nov 05 '22 at 02:58
  • How would you convert that list back into a single number? Knowing it's the same base? ex: 577 in this case – Andrei M. Jul 25 '23 at 14:46
126

If you need compatibility with ancient versions of Python, you can either use gmpy (which does include a fast, completely general int-to-string conversion function, and can be built for such ancient versions – you may need to try older releases since the recent ones have not been tested for venerable Python and GMP releases, only somewhat recent ones), or, for less speed but more convenience, use Python code – e.g., for Python 2, most simply:

import string
digs = string.digits + string.ascii_letters


def int2base(x, base):
    if x < 0:
        sign = -1
    elif x == 0:
        return digs[0]
    else:
        sign = 1

    x *= sign
    digits = []

    while x:
        digits.append(digs[int(x % base)])
        x = int(x / base)

    if sign < 0:
        digits.append('-')

    digits.reverse()

    return ''.join(digits)

For Python 3, int(x / base) leads to incorrect results, and must be changed to x // base:

import string
digs = string.digits + string.ascii_letters


def int2base(x, base):
    if x < 0:
        sign = -1
    elif x == 0:
        return digs[0]
    else:
        sign = 1

    x *= sign
    digits = []

    while x:
        digits.append(digs[x % base])
        x = x // base

    if sign < 0:
        digits.append('-')

    digits.reverse()

    return ''.join(digits)
Alex Huszagh
  • 13,272
  • 3
  • 39
  • 67
Alex Martelli
  • 854,459
  • 170
  • 1,222
  • 1,395
  • 12
    Just in (gmpy2) case the func Alex speaks of seems to be `gmpy2.digits(x, base)`. – mlvljr Jan 02 '12 at 08:03
  • 2
    It was brought to my attention that some cases need a base > 36 and so digs should be `digs = string.digits + string.lowercase + string.uppercase` – Paul Nov 29 '12 at 11:54
  • 4
    (or `string.digits + string.letters`) – kojiro Sep 25 '13 at 03:59
  • 4
    Any idea why the convert-base-N-to-string isn't included by default in Python? (It is in Javascript.) Yeah, we can all write our own implementation, but I've been searching around on this site and elsewhere, and many of them have bugs. Better to have one tested, reputable version included in the core distribution. – Jason S Feb 05 '14 at 21:02
  • 1
    Found a small bug in this excellent routine for the zero case when using a number system that does not start with '0'. Only a one line change, instead of elif x==0: return '0' =====> needs to be elif x==0: return digs[0] – Paul May 05 '14 at 16:06
  • Might be good to add a check that 2 <= base <= 62. Otherwise, if e.g. 1 is passed in for base, it will go into an infinite loop. – twasbrillig Dec 03 '14 at 09:16
  • 1
    Should the reverse be there? >>> int2base(26, 26) 'BA' With reverse taken out: >>> int2base(26, 26) 'AB' – dalore Jan 14 '15 at 13:07
  • 1
    In Python 2, use `string.ascii_letters` instead of `string.letters`. Works in at least Python 2.7 too; haven't tested 2.6. – alexia Jun 13 '15 at 12:49
  • 1
    `string.letters` won't work on Python 3, you need to use `string.ascii_letters`. See here in this [question](http://stackoverflow.com/questions/9561432/what-is-the-equivalence-in-python-3-of-letters-in-python-2) – Cassio Cabral Oct 27 '15 at 00:31
  • 1
    I have found that in Python 3 (tested with 3.4.3 on Windows) the `x /= base` will cause problems because the integer will become a decimal number. I fixed it with `x = int(x / base)` – lordscales91 May 04 '16 at 17:42
  • 1
    Add `if base == 1: return ''.join(['1' for _ in range(x)])` to the start of the function for [unary (base-1)](https://en.wikipedia.org/wiki/Unary_numeral_system) support ;) – 101 Sep 19 '16 at 06:13
  • 5
    @lordscales91 You can also use `x //= base` which behaves like `/=` in Python 2 in dropping the decimal. This answer should include a disclaimer that it's for Python 2. – Noumenon Mar 27 '17 at 16:33
  • Sooner or later someone will get an obscenity as a result of this, as I just realised (in testing, fortunately, as my users would *not* smile and move on). Solution - have a different set of digs that excludes vowels – havlock Nov 13 '18 at 17:38
  • 1
    `int(x / base)` still leads to incorrect results. The correct fix is `x // base`. – WGH Feb 02 '19 at 14:04
  • @WGH what special cases would cause that issue? – vikarjramun Apr 04 '20 at 05:49
  • @vikarjramun A great example is `9223372036854776832`, or `((1<<53)+1) << 10`. Using `x // base` gives the correct result, `1000000000000000000000000000000000000000000000000000010000000000`, while using the code in the sample will give `1000000000000000000000000000000000000000000000000000000000000000`. – Alex Huszagh Aug 12 '21 at 22:33
  • @AlexanderHuszagh ah, so the issue is imprecision of floating point arithmetic. – vikarjramun Aug 13 '21 at 04:08
121
"{0:b}".format(100) # bin: 1100100
"{0:x}".format(100) # hex: 64
"{0:o}".format(100) # oct: 144
Rost
  • 3,602
  • 2
  • 21
  • 21
  • 75
    But it only does those three bases? – Thomas Ahle Oct 04 '11 at 14:48
  • 4
    Yes, unfortunately you can't specify custom int base. More info is here: http://docs.python.org/library/string.html#formatstrings – Rost Oct 06 '11 at 09:25
  • 3
    The `0` is unnecessary. Here's the Python 2 documentation: https://docs.python.org/2/library/string.html#format-string-syntax – Evgeni Sergeev Aug 14 '16 at 04:48
  • 12
    You can achieve the same results with `hex(100)[2:]`, `oct(100)[2:]` and `bin(100)[2:]`. – Sassan Sep 10 '16 at 08:26
  • 3
    @EvgeniSergeev: It's only unnecessary on 2.7/3.1+. On 2.6, the explicit position (or name) is required. – ShadowRanger Apr 04 '17 at 20:09
  • Just a minor correction to @ Sassan's comment above - for oct, it should be `oct(100)[1:]` not `oct(100)[2:]`. (oct numbers are represented by a single leading 0). – Hari Nov 25 '17 at 19:07
  • I think you're mistaken @Hari: [The Python docs](https://docs.python.org/3/library/functions.html#oct) say `oct` does the following: `Convert an integer number to an octal string prefixed with “0o”.`, and I also was able to confirm that on my own interpreter. – Graham Jul 13 '18 at 19:44
103
def baseN(num,b,numerals="0123456789abcdefghijklmnopqrstuvwxyz"):
    return ((num == 0) and numerals[0]) or (baseN(num // b, b, numerals).lstrip(numerals[0]) + numerals[num % b])

ref: http://code.activestate.com/recipes/65212/

Please be aware that this may lead to

RuntimeError: maximum recursion depth exceeded in cmp

for very big integers.

pppery
  • 3,731
  • 22
  • 33
  • 46
jellyfishtree
  • 1,811
  • 1
  • 10
  • 11
  • 5
    Elegant in its brevity. It seems to work under python 2.2.3 for non-negative integers. A negative number infinitely recurses. – Mark Borgerding Feb 15 '10 at 17:04
  • +1 useful; fixed a problem when numerals didn't start with '0' – sehe Sep 14 '11 at 09:57
  • 4
    This fails silently (a) when base is > `len(numerals)`, and (b) `num % b` is, by luck, < `len(numerals)`. e.g. although the `numerals` string is only 36 characters in length, baseN(60, 40) returns `'1k'` while baseN(79, 40) raises an `IndexError`. Both should raise some kind of error. The code should be revised to raise an error if `not 2 <= base <= len(numerals)`. – Chris Johnson Oct 09 '13 at 15:32
  • @ChrisJohnson, only if your base is not fixed in advance. – Sergey Orshanskiy Jan 07 '15 at 22:31
  • 3
    @osa, my point is the code as-written fails in a very bad way (silently, giving misleading answer) and could be fixed easily. If you are saying there would be no error if you knew in advance, for certain, that `b` would not exceed `len(numerals)`, well, good luck to you. – Chris Johnson Jan 07 '15 at 23:36
  • I guess it's questionable whether the "1k" result is really wrong or not. If we give a long enough string of numerals, the result is still the same. The IndexError should clearly be handled though. – Ariel Jan 26 '16 at 13:54
  • +1 for being the smallest bit of code here. The other comments are true, it doesn't properly handle some edge cases, but this is a good substitute when you have a known, limited set of bases and inputs, and limited access to third-party libraries. – EKW Sep 16 '17 at 21:56
  • My friend and I were debating a "better approximate Pi day in a different base", so I modified your code to handle floats: https://gist.github.com/tigerhawkvok/5c619465f9ccab0eb25ee470708bbf16 (the answer is "Base 11 Pi Day" on March 16 at 3:07:02 PM, `3.16150702865a484`) – Philip Kahn Mar 15 '18 at 00:00
  • 3
    The use of short-circuiting here seems needlessly confusing...why not just use an if statement...the line `return numerals[0] if num == 0 else baseN(num // b, b, numerals).lstrip(numerals[0]) + numerals[num % b]` is just as brief. – Ian Hincks Jun 13 '18 at 21:17
  • Alternatively, `def num2str(num, chars): return chars[num] if num < len(chars) else num2str(num // len(chars)) + chars[num % len(chars)]`. Then you can create functions for radixes you need. Or one function (a wrapper) for an arbitrary radix. And as you can see `lstrip()` can be avoided. – x-yuri May 28 '22 at 11:49
  • Inverse to this (string to integer) in case anyone needs it: ```def n_base(num, b, numerals="0123456789abcdefghijklmnopqrstuvwxyz"): return 0 if len(num) == 0 else numerals.find(num[-1]) + n_base(num[:-1], b, numerals) * b``` – Hannes Landeholm Aug 16 '23 at 21:36
74
>>> numpy.base_repr(10, base=3)
'101'

Note that numpy.base_repr() has a limit of 36 as its base. Otherwise it throws a ValueError

Eric Duminil
  • 52,989
  • 9
  • 71
  • 124
V. Ayrat
  • 2,499
  • 9
  • 10
  • Nice solution. In my case, I was avoiding numpy in `clac` for loading-time concerns. Preloading numpy more than triples the runtime of simple expression evaluation in clac: e.g. `clac 1+1` went from about 40ms to 140ms. – Mark Borgerding Jun 03 '19 at 20:20
  • Which matches the limitation of the built in "int" function. Larger bases require deciding on what to do when the letters run out, – plugwash Jan 18 '20 at 14:46
  • I guess this is what most people who reach this question are looking for. – Pietro Battiston Oct 28 '22 at 20:44
35

Recursive

I would simplify the most voted answer to:

base_string = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
def to_base(number, base): 
    return "0" if not number else to_base(number // base, base).lstrip("0") + base_string[number % base_string]

With the same advice for RuntimeError: maximum recursion depth exceeded in cmp on very large integers and negative numbers. (You could usesys.setrecursionlimit(new_limit))

Iterative

To avoid recursion problems:

base_string = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
def to_base(number, base):
    result = ""
    while number:
        result += base_string[number % base]
        number //= base
    return result[::-1] or "0"
gwaadie
  • 15
  • 5
M.M
  • 2,254
  • 1
  • 20
  • 33
22

Great answers! I guess the answer to my question was "no" I was not missing some obvious solution. Here is the function I will use that condenses the good ideas expressed in the answers.

  • allow caller-supplied mapping of characters (allows base64 encode)
  • checks for negative and zero
  • maps complex numbers into tuples of strings


def int2base(x,b,alphabet='0123456789abcdefghijklmnopqrstuvwxyz'):
    'convert an integer to its string representation in a given base'
    if b<2 or b>len(alphabet):
        if b==64: # assume base64 rather than raise error
            alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
        else:
            raise AssertionError("int2base base out of range")
    if isinstance(x,complex): # return a tuple
        return ( int2base(x.real,b,alphabet) , int2base(x.imag,b,alphabet) )
    if x<=0:
        if x==0:
            return alphabet[0]
        else:
            return  '-' + int2base(-x,b,alphabet)
    # else x is non-negative real
    rets=''
    while x>0:
        x,idx = divmod(x,b)
        rets = alphabet[idx] + rets
    return rets

ivan_pozdeev
  • 33,874
  • 19
  • 107
  • 152
Mark Borgerding
  • 8,117
  • 4
  • 30
  • 51
15

You could use baseconv.py from my project: https://github.com/semente/python-baseconv

Sample usage:

>>> from baseconv import BaseConverter
>>> base20 = BaseConverter('0123456789abcdefghij')
>>> base20.encode(1234)
'31e'
>>> base20.decode('31e')
'1234'
>>> base20.encode(-1234)
'-31e'
>>> base20.decode('-31e')
'-1234'
>>> base11 = BaseConverter('0123456789-', sign='$')
>>> base11.encode('$1234')
'$-22'
>>> base11.decode('$-22')
'$1234'

There is some bultin converters as for example baseconv.base2, baseconv.base16 and baseconv.base64.

iBug
  • 35,554
  • 7
  • 89
  • 134
semente
  • 7,265
  • 3
  • 34
  • 35
5
def base(decimal ,base) :
    list = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    other_base = ""
    while decimal != 0 :
        other_base = list[decimal % base] + other_base
        decimal    = decimal / base
    if other_base == "":
        other_base = "0"
    return other_base

print base(31 ,16)

output:

"1F"

user2683246
  • 3,399
  • 29
  • 31
mukundan
  • 99
  • 1
  • 1
5
def base_conversion(num, base):
    digits = []
    while num > 0:
        num, remainder = divmod(num, base)
        digits.append(remainder)
    return digits[::-1]
hxuanhung
  • 103
  • 2
  • 9
  • By replacing the last line with `return ''.join(map(str, digits[::-1]))`, it's even more useful in bases between 2 and 10. It's not working for base 1. – Wolf Apr 29 '22 at 08:18
  • It also doesn't work with `num=0`. – Wolf Apr 29 '22 at 08:46
3

http://code.activestate.com/recipes/65212/

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

Here's another one from the same link

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
John La Rooy
  • 295,403
  • 53
  • 369
  • 502
3

I made a pip package for this.

I recommend you use my bases.py https://github.com/kamijoutouma/bases.py which was inspired by bases.js

from bases import Bases
bases = Bases()

bases.toBase16(200)                // => 'c8'
bases.toBase(200, 16)              // => 'c8'
bases.toBase62(99999)              // => 'q0T'
bases.toBase(200, 62)              // => 'q0T'
bases.toAlphabet(300, 'aAbBcC')    // => 'Abba'

bases.fromBase16('c8')               // => 200
bases.fromBase('c8', 16)             // => 200
bases.fromBase62('q0T')              // => 99999
bases.fromBase('q0T', 62)            // => 99999
bases.fromAlphabet('Abba', 'aAbBcC') // => 300

refer to https://github.com/kamijoutouma/bases.py#known-basesalphabets for what bases are usable

EDIT: pip link https://pypi.python.org/pypi/bases.py/0.2.2

Belldandu
  • 2,176
  • 1
  • 15
  • 16
1
def int2base(a, base, numerals="0123456789abcdefghijklmnopqrstuvwxyz"):
    baseit = lambda a=a, b=base: (not a) and numerals[0]  or baseit(a-a%b,b*base)+numerals[a%b%(base-1) or (a%b) and (base-1)]
    return baseit()

explanation

In any base every number is equal to a1+a2*base**2+a3*base**3... The "mission" is to find all a 's.

For everyN=1,2,3... the code is isolating the aN*base**N by "mouduling" by b for b=base**(N+1) which slice all a 's bigger than N, and slicing all the a 's that their serial is smaller than N by decreasing a everytime the func is called by the current aN*base**N .

Base%(base-1)==1 therefor base**p%(base-1)==1 and therefor q*base^p%(base-1)==q with only one exception when q=base-1 which returns 0. To fix that in case it returns 0 the func is checking is it 0 from the beggining.


advantages

in this sample theres only one multiplications (instead of division) and some moudulueses which relatively takes small amounts of time.

Community
  • 1
  • 1
Shu ba
  • 334
  • 1
  • 10
1

While the currently top answer is definitely an awesome solution, there remains more customization users might like.

Basencode adds some of these features, including conversions of floating point numbers, modifying digits (in the linked answer, only numbers can be used).

Here's a possible use case:

>>> from basencode import *
>>> n1 = Number(12345)
>> n1.repr_in_base(64) # convert to base 64
'30V'
>>> Number('30V', 64) # construct Integer from base 64
Integer(12345)
>>> n1.repr_in_base(8)
'30071'
>>> n1.repr_in_octal() # shortcuts
'30071'
>>> n1.repr_in_bin() # equivelant to `n1.repr_in_base(2)`
'11000000111001'
>>> n1.repr_in_base(2, digits=list('-+')) # override default digits: use `-` and `+` in place of `0` and `1`
'++------+++--+'
>>> n1.repr_in_base(33) # yet another base - all bases from 2 to 64 are supported from the start
'bb3'

How would you add any bases you want? Let me replicate the example of the currently most upvoted answer: the digits parameter allows you to override the default digits from base 2 to 64, and provide digits for any base higher than that. The mode parameter determines how the value of the representation will determine how (list or string) the answer will be returned.

>>> n2 = Number(67854 ** 15 - 102)
>>> n2.repr_in_base(577, digits=[str(i) for i in range(577)], mode="l")
['4', '473', '131', '96', '431', '285', '524', '486', '28', '23', '16', '82', '292', '538', '149', '25', '41', '483', '100', '517', '131', '28', '0', '435', '197', '264', '455']
>>> n2.repr_in_base(577, mode="l") # the program remembers the digits for base 577 now
['4', '473', '131', '96', '431', '285', '524', '486', '28', '23', '16', '82', '292', '538', '149', '25', '41', '483', '100', '517', '131', '28', '0', '435', '197', '264', '455']

Operations can be done: the Number class returns an instance of basencode.Integer if the provided number is an Integer, else it returns a basencode.Float

>>> n3 = Number(54321) # the Number class returns an instance of `basencode.Integer` if the provided number is an Integer, otherwise it returns a `basencode.Float`.
>>> n1 + n3
Integer(66666)
>>> n3 - n1
Integer(41976)
>>> n1 * n3
Integer(670592745)
>>> n3 // n1
Integer(4)
>>> n3 / n1 # a basencode.Float class allows conversion of floating point numbers
Float(4.400243013365735)
>>> (n3 / n1).repr_in_base(32)
'4.cpr56v6rnc4oitoblha2r11sus0dheqd4pgechfcjklo74b2bgom7j8ih86mipdvss0068sehi9f3791mdo4uotfujq66cf0jkgo'
>>> n4 = Number(0.5) # returns a basencode.Float
>>> n4.repr_in_bin() # binary version of 0.5
'0.1'

Disclaimer: this project is under active maintenance, and I'm a contributor.

Safwan Samsudeen
  • 1,645
  • 1
  • 10
  • 25
0
>>> import string
>>> def int2base(integer, base):
        if not integer: return '0'
        sign = 1 if integer > 0 else -1
        alphanum = string.digits + string.ascii_lowercase
        nums = alphanum[:base]
        res = ''
        integer *= sign
        while integer:
                integer, mod = divmod(integer, base)
                res += nums[mod]
        return ('' if sign == 1 else '-') + res[::-1]


>>> int2base(-15645, 23)
'-16d5'
>>> int2base(213, 21)
'a3'
SilentGhost
  • 307,395
  • 66
  • 306
  • 293
0

A recursive solution for those interested. Of course, this will not work with negative binary values. You would need to implement Two's Complement.

def generateBase36Alphabet():
    return ''.join([str(i) for i in range(10)]+[chr(i+65) for i in range(26)])

def generateAlphabet(base):
    return generateBase36Alphabet()[:base]

def intToStr(n, base, alphabet):
    def toStr(n, base, alphabet):
        return alphabet[n] if n < base else toStr(n//base,base,alphabet) + alphabet[n%base]
    return ('-' if n < 0 else '') + toStr(abs(n), base, alphabet)

print('{} -> {}'.format(-31, intToStr(-31, 16, generateAlphabet(16)))) # -31 -> -1F
Mr. Polywhirl
  • 42,981
  • 12
  • 84
  • 132
0

Strings aren't the only choice for representing numbers: you can use a list of integers to represent the order of each digit. Those can easily be converted to a string.

None of the answers reject base < 2; and most will run very slowly or crash with stack overflows for very large numbers (such as 56789 ** 43210). To avoid such failures, reduce quickly like this:

def n_to_base(n, b):
    if b < 2: raise # invalid base
    if abs(n) < b: return [n]
    ret = [y for d in n_to_base(n, b*b) for y in divmod(d, b)]
    return ret[1:] if ret[0] == 0 else ret # remove leading zeros

def base_to_n(v, b):
    h = len(v) // 2
    if h == 0: return v[0]
    return base_to_n(v[:-h], b) * (b**h) + base_to_n(v[-h:], b)

assert ''.join(['0123456789'[x] for x in n_to_base(56789**43210,10)])==str(56789**43210)

Speedwise, n_to_base is comparable with str for large numbers (about 0.3s on my machine), but if you compare against hex you may be surprised (about 0.3ms on my machine, or 1000x faster). The reason is because the large integer is stored in memory in base 256 (bytes). Each byte can simply be converted to a two-character hex string. This alignment only happens for bases that are powers of two, which is why there are special cases for 2,8, and 16 (and base64, ascii, utf16, utf32).

Consider the last digit of a decimal string. How does it relate to the sequence of bytes that forms its integer? Let's label the bytes s[i] with s[0] being the least significant (little endian). Then the last digit is sum([s[i]*(256**i) % 10 for i in range(n)]). Well, it happens that 256**i ends with a 6 for i > 0 (6*6=36) so that last digit is (s[0]*5 + sum(s)*6)%10. From this, you can see that the last digit depends on the sum of all the bytes. This nonlocal property is what makes converting to decimal harder.

colski
  • 19
  • 2
0
def base_changer(number,base):
    buff=97+abs(base-10)
    dic={};buff2='';buff3=10
    for i in range(97,buff+1):
        dic[buff3]=chr(i)
        buff3+=1   
    while(number>=base):
        mod=int(number%base)
        number=int(number//base)
        if (mod) in dic.keys():
            buff2+=dic[mod]
            continue
        buff2+=str(mod)
    if (number) in dic.keys():
        buff2+=dic[number]
    else:
        buff2+=str(number)

    return buff2[::-1]   
montaqami
  • 9
  • 2
0

Here is an example of how to convert a number of any base to another base.

from collections import namedtuple

Test = namedtuple("Test", ["n", "from_base", "to_base", "expected"])


def convert(n: int, from_base: int, to_base: int) -> int:
    digits = []
    while n:
        (n, r) = divmod(n, to_base)
        digits.append(r)    
    return sum(from_base ** i * v for i, v in enumerate(digits))


if __name__ == "__main__":
    tests = [
        Test(32, 16, 10, 50),
        Test(32, 20, 10, 62),
        Test(1010, 2, 10, 10),
        Test(8, 10, 8, 10),
        Test(150, 100, 1000, 150),
        Test(1500, 100, 10, 1050000),
    ]

    for test in tests:
        result = convert(*test[:-1])
        assert result == test.expected, f"{test=}, {result=}"
    print("PASSED!!!")
Vlad Bezden
  • 83,883
  • 25
  • 248
  • 179
0

Say we want to convert 14 to base 2. We repeatedly apply the division algorithm until the quotient is 0:

14 = 2 x 7

7 = 2 x 3 + 1

3 = 2 x 1 + 1

1 = 2 x 0 + 1

The binary representation is just the remainder read from bottom to top. This can be proved by expanding

14 = 2 x 7 = 2 x (2 x 3 + 1) = 2 x (2 x (2 x 1 + 1) + 1) = 2 x (2 x (2 x (2 x 0 + 1) + 1) + 1) = 2^3 + 2^2 + 2

The code is the implementation of the above algorithm.

def toBaseX(n, X):
strbin = ""
while n != 0:
    strbin += str(n % X)
    n = n // X
return strbin[::-1]
Adola
  • 337
  • 1
  • 16
0

This is my approach. At first converting the number then casting it to string.

    def to_base(n, base):
        if base == 10:
            return n
        
        result = 0
        counter = 0
        
        while n:
            r = n % base
            n //= base
            result += r * 10**counter
            counter+=1
        return str(result)
princebillyGK
  • 2,917
  • 1
  • 26
  • 20
0

I have written this function which I use to encode in different bases. I also provided the way to shift the result by a value 'offset'. This is useful if you'd like to encode to bases above 64, but keeping displayable chars (like a base 95).

I also tried to avoid reversing the output 'list' and tried to minimize computing operations. The array of pow(base) is computed on demand and kept for additional calls to the function.

The output is a binary string

pows = {}

######################################################
def encode_base(value,
                base = 10,
                offset = 0) :

    """
    Encode value into a binary string, according to the desired base.

    Input :
        value : Any positive integer value
        offset : Shift the encoding (eg : Starting at chr(32))
        base : The base in which we'd like to encode the value

    Return : Binary string

    Example : with : offset = 32, base = 64

              100 -> !D
              200 -> #(
    """

    # Determine the number of loops
    try :
        pb = pows[base]

    except KeyError :
        pb = pows[base] = {n : base ** n for n in range(0, 8) if n < 2 ** 48 -1}

    for n in pb :
        if value < pb[n] :
            n -= 1
            break

    out = []
    while n + 1 :
        b = pb[n]
        out.append(chr(offset + value // b))
        n -= 1
        value %= b

    return ''.join(out).encode()
dcexcal
  • 197
  • 7
0

This function converts any integer from any base to any base

def baseconvert(number, srcbase, destbase):
    if srcbase != 10:
        sum = 0
        for _ in range(len(str(number))):
            sum += int(str(number)[_]) * pow(srcbase, len(str(number)) - _ - 1)
        b10 = sum
        return baseconvert(b10, 10, destbase)
    end = ''
    q = number
    while(True):
        r = q % destbase
        q = q // destbase
        end = str(r) + end
        if(q<destbase):
            end = str(q) + end
            return int(end)
0

The below provided Python code converts a Python integer to a string in arbitrary base ( from 2 up to infinity ) and works in both directions. So all the created strings can be converted back to Python integers by providing a string for N instead of an integer. The code works only on positive numbers by intention (there is in my eyes some hassle about negative values and their bit representations I don't want to dig into). Just pick from this code what you need, want or like, or just have fun learning about available options. Much is there only for the purpose of documenting all the various available approaches ( e.g. the Oneliner seems not to be fast, even if promised to be ).

I like the by Salvador Dali proposed format for infinite large bases. A nice proposal which works optically well even for simple binary bit representations. Notice that the width=x padding parameter in case of infiniteBase=True formatted string applies to the digits and not to the whole number. It seems, that code handling infiniteBase digits format runs even a bit faster than the other options - another reason for using it?

I don't like the idea of using Unicode for extending the number of symbols available for digits, so don't look in the code below for it, because it's not there. Use the proposed infiniteBase format instead or store integers as bytes for compression purposes.

    def inumToStr( N, base=2, width=1, infiniteBase=False,\
    useNumpy=False, useRecursion=False, useOneliner=False, \
    useGmpy=False, verbose=True):
    ''' Positive numbers only, but works in BOTH directions.
    For strings in infiniteBase notation set for bases <= 62 
    infiniteBase=True . Examples of use:
    inumToStr( 17,  2, 1, 1)             # [1,0,0,0,1]
    inumToStr( 17,  3, 5)                #       00122
    inumToStr(245, 16, 4)                #        00F5
    inumToStr(245, 36, 4,0,1)            #        006T
    inumToStr(245245245245,36,10,0,1)    #  0034NWOQBH
    inumToStr(245245245245,62)           #     4JhA3Th 
        245245245245 == int(gmpy2.mpz('4JhA3Th',62))
    inumToStr(245245245245,99,2) # [25,78, 5,23,70,44]
    ----------------------------------------------------
    inumToStr( '[1,0,0,0,1]',2, infiniteBase=True ) # 17 
    inumToStr( '[25,78, 5,23,70,44]', 99) # 245245245245
    inumToStr( '0034NWOQBH', 36 )         # 245245245245 
    inumToStr( '4JhA3Th'   , 62 )         # 245245245245
    ----------------------------------------------------
    --- Timings for N = 2**4096, base=36: 
                                      standard: 0.0023
                                      infinite: 0.0017
                                      numpy   : 0.1277
                                      recursio; 0.0022
                                      oneliner: 0.0146
                For N = 2**8192: 
                                      standard: 0.0075
                                      infinite: 0.0053
                                      numpy   : 0.1369
    max. recursion depth exceeded:    recursio/oneliner
    '''
    show = print
    if type(N) is str and ( infiniteBase is True or base > 62 ):
        lstN = eval(N)
        if verbose: show(' converting a non-standard infiniteBase bits string to Python integer')
        return sum( [ item*base**pow for pow, item in enumerate(lstN[::-1]) ] )
    if type(N) is str and base <= 36:
        if verbose: show('base <= 36. Returning Python int(N, base)')
        return int(N, base)
    if type(N) is str and base <= 62:
        if useGmpy: 
            if verbose: show(' base <= 62, useGmpy=True, returning int(gmpy2.mpz(N,base))')
            return int(gmpy2.mpz(N,base))
        else:
            if verbose: show(' base <= 62, useGmpy=False, self-calculating return value)')
            lstStrOfDigits="0123456789"+ \
                "abcdefghijklmnopqrstuvwxyz".upper() + \
                "abcdefghijklmnopqrstuvwxyz"
            dictCharToPow = {}
            for index, char in enumerate(lstStrOfDigits):
                dictCharToPow.update({char : index}) 
            return sum( dictCharToPow[item]*base**pow for pow, item in enumerate(N[::-1]) )
        #:if
    #:if        
        
    if useOneliner and base <= 36:  
        if verbose: show(' base <= 36, useOneliner=True, running the Oneliner code')
        d="0123456789abcdefghijklmnopqrstuvwxyz"
        baseit = lambda a=N, b=base: (not a) and d[0]  or \
        baseit(a-a%b,b*base)+d[a%b%(base-1) or (a%b) and (base-1)]
        return baseit().rjust(width, d[0])[1:]

    if useRecursion and base <= 36: 
        if verbose: show(' base <= 36, useRecursion=True, running recursion algorythm')
        BS="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
        def to_base(n, b): 
            return "0" if not n else to_base(n//b, b).lstrip("0") + BS[n%b]
        return to_base(N, base).rjust(width,BS[0])
        
    if base > 62 or infiniteBase:
        if verbose: show(' base > 62 or infiniteBase=True, returning a non-standard digits string')
        # Allows arbitrary large base with 'width=...' 
        # applied to each digit (useful also for bits )
        N, digit = divmod(N, base)
        strN = str(digit).rjust(width, ' ')+']'
        while N:
            N, digit = divmod(N, base)
            strN = str(digit).rjust(width, ' ') + ',' + strN
        return '[' + strN
    #:if        
    
    if base == 2:
        if verbose: show(" base = 2, returning Python str(f'{N:0{width}b}')")
        return str(f'{N:0{width}b}')
    if base == 8:
        if verbose: show(" base = 8, returning Python str(f'{N:0{width}o}')")
        return str(f'{N:0{width}o}')
    if base == 16:
        if verbose: show(" base = 16, returning Python str(f'{N:0{width}X}')")
        return str(f'{N:0{width}X}')

    if base <= 36:
        if useNumpy: 
            if verbose: show(" base <= 36, useNumpy=True, returning np.base_repr(N, base)")
            import numpy as np
            strN = np.base_repr(N, base)
            return strN.rjust(width, '0') 
        else:
            if verbose: show(' base <= 36, useNumpy=False, self-calculating return value)')
            lstStrOfDigits="0123456789"+"abcdefghijklmnopqrstuvwxyz".upper()
            strN = lstStrOfDigits[N % base] # rightmost digit
            while N >= base:
                N //= base # consume already converted digit
                strN = lstStrOfDigits[N % base] + strN # add digits to the left
            #:while
            return strN.rjust(width, lstStrOfDigits[0])
        #:if
    #:if
    
    if base <= 62:
        if useGmpy: 
            if verbose: show(" base <= 62, useGmpy=True, returning gmpy2.digits(N, base)")
            import gmpy2
            strN = gmpy2.digits(N, base)
            return strN.rjust(width, '0') 
            # back to Python int from gmpy2.mpz with 
            #     int(gmpy2.mpz('4JhA3Th',62))
        else:
            if verbose: show(' base <= 62, useGmpy=False, self-calculating return value)')
            lstStrOfDigits= "0123456789" + \
                "abcdefghijklmnopqrstuvwxyz".upper() + \
                "abcdefghijklmnopqrstuvwxyz"
            strN = lstStrOfDigits[N % base] # rightmost digit
            while N >= base:
                N //= base # consume already converted digit
                strN = lstStrOfDigits[N % base] + strN # add digits to the left
            #:while
            return strN.rjust(width, lstStrOfDigits[0])
        #:if
    #:if    
#:def
Claudio
  • 7,474
  • 3
  • 18
  • 48
0

I'm presenting a "unoptimized" solution for bases between 2 and 9:

  def to_base(N, base=2):
    N_in_base = ''
    while True:
        N_in_base = str(N % base) + N_in_base
        N //= base
        if N == 0:
            break
    return N_in_base

This solution does not require reversing the final result, but it's actually not optimized. Refer to this answer to see why: https://stackoverflow.com/a/37133870/7896998

Hou
  • 69
  • 1
  • 1
  • 5
0

Simple base transformation

def int_to_str(x, b):
    s = ""
    while x:
        s = str(x % b) + s
        x //= b
    return s

Example of output with no 0 to base 9

s = ""
x = int(input())
while x:
    if x % 9 == 0:
        s = "9" + s
        x -= x % 10
        x = x // 9
    else:
        s = str(x % 9) + s
        x = x // 9

print(s)
dmitry_romanov
  • 5,146
  • 1
  • 33
  • 36
-1
def dec_to_radix(input, to_radix=2, power=None):
    if not isinstance(input, int):
        raise TypeError('Not an integer!')
    elif power is None:
        power = 1

    if input == 0:
        return 0
    else:
        remainder = input % to_radix**power
        digit = str(int(remainder/to_radix**(power-1)))
        return int(str(dec_to_radix(input-remainder, to_radix, power+1)) + digit)

def radix_to_dec(input, from_radix):
    if not isinstance(input, int):
        raise TypeError('Not an integer!')
    return sum(int(digit)*(from_radix**power) for power, digit in enumerate(str(input)[::-1]))

def radix_to_radix(input, from_radix=10, to_radix=2, power=None):
    dec = radix_to_dec(input, from_radix)
    return dec_to_radix(dec, to_radix, power)
-1
def baseConverter(x, b):
    s = ""
    d = string.printable.upper()
    while x > 0:
        s += d[x%b]
        x = x / b
    return s[::-1]
jay a
  • 624
  • 2
  • 7
  • 11
gjivanya
  • 519
  • 2
  • 6
  • 19
  • For python3 your code does this: baseConverter(0, 26) -> '' baseConverter(1, 26) -> '0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001' For python2 it does this: baseConverter(0, 26) -> '' baseConverter(1, 26) -> 1 baseConverter(3, 26) -> 3 baseConverter(5, 26) -> 5 baseConverter(26, 26) -> 10 baseConverter(32, 26) -> 16 – Drachenfels Apr 20 '17 at 12:25
-1

Another short one (and easier to understand imo):

def int_to_str(n, b, symbols='0123456789abcdefghijklmnopqrstuvwxyz'):
    return (int_to_str(n/b, b, symbols) if n >= b else "") + symbols[n%b]

And with proper exception handling:

def int_to_str(n, b, symbols='0123456789abcdefghijklmnopqrstuvwxyz'):
    try:
        return (int_to_str(n/b, b) if n >= b else "") + symbols[n%b]
    except IndexError:
        raise ValueError(
            "The symbols provided are not enough to represent this number in "
            "this base")
Ariel
  • 3,383
  • 4
  • 43
  • 58
-1

Here is a recursive version that handles signed integers and custom digits.

import string

def base_convert(x, base, digits=None):
    """Convert integer `x` from base 10 to base `base` using `digits` characters as digits.
    If `digits` is omitted, it will use decimal digits + lowercase letters + uppercase letters.
    """
    digits = digits or (string.digits + string.ascii_letters)
    assert 2 <= base <= len(digits), "Unsupported base: {}".format(base)
    if x == 0:
        return digits[0]
    sign = '-' if x < 0 else ''
    x = abs(x)
    first_digits = base_convert(x // base, base, digits).lstrip(digits[0])
    return sign + first_digits + digits[x % base]
Antoine Pinsard
  • 33,148
  • 8
  • 67
  • 87
-1
num = input("number")
power = 0
num = int(num)
while num > 10:
    num = num / 10
    power += 1

print(str(round(num, 2)) + "^" + str(power))
Casey Howard
  • 21
  • 1
  • 4
  • please add some brief information that what you did special init – Farhana Naaz Ansari Nov 15 '18 at 04:29
  • While this might answer the authors question, it lacks some explaining words and/or links to documentation. Raw code snippets are not very helpful without some phrases around them. You may also find [how to write a good answer](https://stackoverflow.com/help/how-to-answer) very helpful. Please edit your answer. – hellow Nov 15 '18 at 07:48
-1

Well I personally use this function, written by me

import string

def to_base(value, base, digits=string.digits+string.ascii_letters):    # converts decimal to base n

    digits_slice = digits[0:base]

    temporary_var = value
    data = [temporary_var]

    while True:
        temporary_var = temporary_var // base
        data.append(temporary_var)
        if temporary_var < base:
            break

    result = ''
    for each_data in data:
        result += digits_slice[each_data % base]
    result = result[::-1]

    return result

This is how you can use it

print(to_base(7, base=2))

Output: "111"

print(to_base(23, base=3))

Output: "212"

Please feel free to suggest improvements in my code.

Artaza Sameen
  • 519
  • 1
  • 5
  • 13
-1

This is an old question but I thought i'd share my take on it as I feel it is somewhat simpler that other answers (good for bases from 2 to 36):

def intStr(n,base=10):
    if n < 0   : return "-" + intStr(-n,base)         # handle negatives
    if n < base: return chr([48,55][n>9] + n)         # 48 => "0"..., 65 => "A"...
    return intStr(n//base,base) + intStr(n%base,base) # recurse for multiple digits
Alain T.
  • 40,517
  • 4
  • 31
  • 51
-1

I know this is an old post, but I'm just leaving my solution here just in case.

def decimal_to_given_base(integer_to_convert, base):
     remainder = integer_to_convert // base
     digit = integer_to_convert % base
     if integer_to_convert == 0:
         return '0'
     elif remainder == 0:
         return str(digit)
     else:
         return decimal_to_given_base(remainder, base) + str(digit)
PSN
  • 2,326
  • 3
  • 27
  • 52
-1

I made my function to do this. Run well on windows 10, python 3.7.3.

def number_to_base(number, base, precision = 10):
    if number == 0:
        return [0]
    
    positive = number >= 0
    number = abs(number)
    
    ints = []  # store the integer bases
    floats = []  # store the floating bases

    float_point = number % 1
    number = int(number)
    while number:
        ints.append(int(number%base))
        number //= base
    ints.reverse()
    
    while float_point and precision:
        precision -= 1
        float_point *= base
        floats.append(int(float_point))
        float_point = float_point - int(float_point)

    return ints, floats, positive


def base_to_str(bases, string="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"):
    """bases is a two dimension list, where bases[0] contains a list of the integers,
    and bases[1] contains a list of the floating numbers, bases[2] is a boolean, that's
    true when it's a positive number
    """
    ints = []
    floats = []

    for i in bases[0]:
        ints.append(string[i])

    for i in bases[1]:
        floats.append(string[i])

    if len(bases[1]) > 0:
        return (["-", ""][bases[2]] + "".join(ints)) + "." + ("".join(floats))
    else:
        return (["-", ""][bases[2]] + "".join(ints))
    

    

Example:

>>> base_to_str(number_to_base(-6.252, 2))
'-110.0100000010'
Hzzkygcs
  • 1,532
  • 2
  • 16
  • 24