How to convert an integer to a string in any base?
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)
Is there a built in function to change the base of an integer in Python?
When you speak of an integer object, it is not the same as its base N representation.
While internally, the integer is stored in binary, the integer object itself has no base. You can construct an int object from any string of digits in any base N, as long as you specify the base and the string of digits is valid for that base. This is usually restricted to a maximum of 36, since there are 10 decimal digits and 26 letters in the alphabet.
There are special cases for the bases 2, 8, 10, and 16, since they are the most used. For those bases, you can specify the base within the string representation itself. You use prefixes of 0b
, 0o
, or 0x
for 2, 8, and 16 respectively. Decimal is the default and the most used, so it requires no prefix.
If you want to return the base N representation of an integer as a string, i.e. invert the operation int(n, N), you have several options. You can use gmpy.digits(n, N)
where n
is your int, and N
is the base you want. This might be overkill, since it requires installing gmpy.
You can alternatively use something like this:
import string
def int_to_base(n, N):
""" Return base N representation for int n. """
base_n_digits = digits + ascii_lowercase + ascii_uppercase
result = ""
if n < 0:
sign = "-"
n = -n
else:
sign = ""
while n > 0:
q, r = divmod(n, N)
result += base_n_digits[r]
n = q
if result == "":
result = "0"
return sign + "".join(reversed(result))
With that function, or something similar to it, you can return the string base N representation of an integer n in base N, so that:
>>> base_n_string = "81"
>>> base = 9
>>> int_to_base(int("81", 9), 9) == "81"
True
How to convert an integer to a string in any base?
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)
Converting a base 10 number to any base without strings
a simple implementation which can "convert" up to base 9 is as follows:
def conver(n,b):
a = 0
i = 0
while n:
n,r = divmod(n,b)
a += 10**i * r
i += 1
return a
note that n,r = divmod(n,b)
could be r = n % b; n //= b
Note that the number you're getting is an integer all right (as a type), but it makes no sense using it as such because the base is wrong: Ex: 1110
is not really 1110
. So it's not really different than a string...
Well, that's just for the sake of the exercise.
Python elegant inverse function of int(string,base)
This thread has some example implementations.
Actually I think your solution looks rather nice, it's even recursive which is somehow pleasing here.
I'd still simplify it to remove the else
, but that's probably a personal style thing. I think if foo: return
is very clear, and doesn't need an else
after it to make it clear it's a separate branch.
def digit_to_char(digit):
if digit < 10:
return str(digit)
return chr(ord('a') + digit - 10)
def str_base(number,base):
if number < 0:
return '-' + str_base(-number, base)
(d, m) = divmod(number, base)
if d > 0:
return str_base(d, base) + digit_to_char(m)
return digit_to_char(m)
I simplified the 0-9 case in digit_to_char()
, I think str()
is clearer than the chr(ord())
construct. To maximize the symmetry with the >= 10
case an ord()
could be factored out, but I didn't bother since it would add a line and brevity felt better. :)
Is there a built-in function that converts a number to a string in any base?
If you wanted to eke out a little more performance, you can create a struct and implement Display
or Debug
for it. This avoids allocating a String
. For maximum over-engineering, you can also have a stack-allocated array instead of the Vec
.
Here is Boiethios' answer with these changes applied:
struct Radix {
x: i32,
radix: u32,
}
impl Radix {
fn new(x: i32, radix: u32) -> Result<Self, &'static str> {
if radix < 2 || radix > 36 {
Err("Unnsupported radix")
} else {
Ok(Self { x, radix })
}
}
}
use std::fmt;
impl fmt::Display for Radix {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut x = self.x;
// Good for binary formatting of `u128`s
let mut result = ['\0'; 128];
let mut used = 0;
let negative = x < 0;
if negative {
x*=-1;
}
let mut x = x as u32;
loop {
let m = x % self.radix;
x /= self.radix;
result[used] = std::char::from_digit(m, self.radix).unwrap();
used += 1;
if x == 0 {
break;
}
}
if negative {
write!(f, "-")?;
}
for c in result[..used].iter().rev() {
write!(f, "{}", c)?;
}
Ok(())
}
}
fn main() {
assert_eq!(Radix::new(1234, 10).to_string(), "1234");
assert_eq!(Radix::new(1000, 10).to_string(), "1000");
assert_eq!(Radix::new(0, 10).to_string(), "0");
}
This could still be optimized by:
- creating an ASCII array instead of a
char
array - not zero-initializing the array
Since these avenues require unsafe
or an external crate like arraybuf, I have not included them. You can see sample code in internal implementation details of the standard library.
Related Topics
Finding and Replacing Elements in a List
How Does Tuple Comparison Work in Python
Why Is "1000000000000000 in Range(1000000000000001)" So Fast in Python 3
What Is the Python Keyword "With" Used For
Pandas Get Rows Which Are Not in Other Dataframe
How to Set Environment Variables in Python
How to Update a Plot in Matplotlib
How to Merge Dictionaries of Dictionaries
How to Open a Chrome Profile Through Python
Text Progress Bar in Terminal With Block Characters
What Is an Alternative to Execfile in Python 3
How to Convert an Integer to a String in Any Base
How to Check Which Version of Python Is Running My Script
Python Requests Throwing Sslerror