que - convertir un string en float python
¿Cómo convertir un entero en cualquier base a una cadena? (23)
¡Excelentes respuestas! Supongo que la respuesta a mi pregunta fue "no". No me faltaba ninguna solución obvia. Aquí está la función que usaré que condensa las buenas ideas expresadas en las respuestas.
- permitir el mapeo de caracteres proporcionado por el que llama (permite codificar base64)
- cheques para negativo y cero
- mapea números complejos en tuplas de cuerdas
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
Python permite la creación fácil de un entero a partir de una cadena de una base dada vía
int(str, base).
Quiero realizar el inverso: creación de una cadena a partir de un entero , es decir, quiero alguna función int2base(num, base)
, tal que:
int(int2base(x, b), b) == x
El nombre de función / orden de argumento no es importante.
Para cualquier número x
base b
que int()
aceptará.
Esta es una función fácil de escribir: de hecho, es más fácil que describirla en esta pregunta. Sin embargo, siento que debo estar perdiendo algo.
Sé sobre las funciones bin
, oct
, hex
, pero no puedo usarlas por varias razones:
Esas funciones no están disponibles en versiones anteriores de Python, con las cuales necesito compatibilidad con (2.2)
Quiero una solución general que pueda llamarse de la misma manera para diferentes bases
Quiero permitir bases que no sean 2, 8, 16
Relacionado
Aquí hay una versión recursiva que maneja enteros con signo y dígitos personalizados.
def baseConverter(x, b):
s = ""
d = string.printable.upper()
while x > 0:
s += d[x%b]
x = x / b
return s[::-1]
Hice un paquete de pip para esto.
Te recomiendo que uses mi base.py https://github.com/kamijoutouma/bases.py que fue inspirado por bases.js
def base(decimal ,base) :
list = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
other_base = ""
while decimal != 0 :
other_base = list[decimal % base] + other_base
decimal = decimal / base
return other_base
print base(31 ,16)
consulte https://github.com/kamijoutouma/bases.py#known-basesalphabets para saber qué bases son utilizables
EDITAR: enlace de pip https://pypi.python.org/pypi/bases.py/0.2.2
Las cadenas no son la única opción para representar números: puede usar una lista de enteros para representar el orden de cada dígito. Esos pueden convertirse fácilmente en una cadena.
Ninguna de las respuestas rechaza base <2; y la mayoría funcionará muy lentamente o se bloqueará con desbordamientos de pila para números muy grandes (como 56789 ** 43210). Para evitar tales fallas, reduzca rápidamente así:
DIGITS = "0123456789abcdefghijklmnopqrstuvwxyz"
# note that the order of the digits is reversed for digits before the point
NO_GROUPING = lambda g: g
concat = "".join
concat_backwards = lambda g: concat(e for e in reversed(list(g)))
def grouping(length = 3, char = ''_''):
def yieldor(digits):
i = 0
for d in digits:
if i == length:
yield char
i = 0
yield d
i+=1
return yieldor
class Converter:
def __init__(self, baseDigits: (int, str), beforePoint = NO_GROUPING, afterPoint = NO_GROUPING, decimalPoint = ''.'', digitPrecision = 16, trimZeros = True):
if isinstance(baseDigits, int):
baseDigits = DIGITS[:baseDigits]
self.baseDigits = baseDigits
self.beforePoint = beforePoint
self.afterPoint = afterPoint
self.decimalPoint = decimalPoint
self.digitPrecision = digitPrecision
self.trimZeros = trimZeros
def to_string(self, number: (int, float, complex)) -> str:
if isinstance(number, complex):
if number.imag == 0:
return self.to_string(number.real)
if number.real == 0:
return self.to_string(number.imag) + ''j''
return "({}+{}j)".format(self.to_string(number.real), self.to_string (number.imag))
if number < 0:
return ''-'' + self.to_string(-number)
digitCount = len(self.baseDigits)
if isinstance(number, float):
# round correctly
precError=digitCount**-self.digitPrecision
number+=0.5*precError
if self.trimZeros:
def yieldor(n):
p = precError
for i in range(self.digitPrecision):
if n <= p:
return
p *= digitCount
n *= digitCount
digit = int(n)
n -= digit
yield self.baseDigits[digit]
else:
def yieldor(n):
for i in range(self.digitPrecision):
n *= digitCount
digit = int(n)
n -= digit
yield self.baseDigits[digit]
a = concat(self.afterPoint(yieldor(number%1)))
return (
self.to_string(int(number)) + (a and self.decimalPoint + a)
)
else: #is int
if not number: return self.baseDigits[0]
def yieldor(n):
while n:
n, digit = divmod(n, digitCount)
yield self.baseDigits[digit]
return concat_backwards(self.beforePoint(yieldor(number)))
# some tests:
if __name__ == "__main__":
def conv_test(num, digits, *argv, **kwv):
print(num, "->", digits if isinstance(digits, int) else "{} ({})".format(len(digits), digits), Converter(digits, *argv, **kwv).to_string(num))
conv_test(True, "ft")
conv_test(123, 12, grouping(2))
conv_test(-0xf00d, 16)
conv_test(1000, True<<True, grouping(4))
conv_test(1_000_000, "0+-", beforePoint = grouping(2, ''|''))
conv_test(1.5, 10)
conv_test(0.999999999, 10, digitPrecision = 8)
conv_test(-0.1, 10)
import math
conv_test(math.pi, 10, afterPoint = grouping(5, '' ''))
conv_test(0.123456789, 10, digitPrecision = 6)
grSpc = grouping(1, '' '')
conv_test(math.e, ["off", "on"], grSpc, grSpc, " dot ", digitPrecision = 7)
conv_test(1 + 1.5j, 10)
conv_test(50j, 10)
conv_test(10.01, ''-<>'')
# and generate some brainfuck-code here:
conv_test(1701**42, ''+-<>,.]['', digitPrecision = 32)
Speedwise, n_to_base
es comparable con str
para grandes cantidades (alrededor de 0.3s en mi máquina), pero si lo comparas contra hex
te sorprenderá (aproximadamente 0.3ms en mi máquina, o 1000x más rápido). La razón es porque el entero grande se almacena en la memoria en la base 256 (bytes). Cada byte puede simplemente convertirse en una cadena hexagonal de dos caracteres. Esta alineación solo ocurre para bases que son potencias de dos, por lo que hay casos especiales para 2,8 y 16 (y base64, ascii, utf16, utf32).
Considere el último dígito de una cadena decimal. ¿Cómo se relaciona con la secuencia de bytes que forma su número entero? Etiquetemos los bytes s[i]
con s[0]
siendo el menos significativo (pequeño endian). Entonces, el último dígito es sum([s[i]*(256**i) % 10 for i in range(n)])
. Bueno, sucede que 256 ** i termina con un 6 para i> 0 (6 * 6 = 36) por lo que el último dígito es (s[0]*5 + sum(s)*6)%10
. A partir de esto, puede ver que el último dígito depende de la suma de todos los bytes. Esta propiedad no local es lo que hace que la conversión a decimal sea más difícil.
No he visto ningún convertidor de flotador aquí. Y me perdí la agrupación por siempre tres dígitos.
QUE HACER:
-números en expresión científica (n.nnnnnn*10**(exp)
- el ''10''
es self.baseDigits[1::-1]/self.to_string(len (self.baseDigits))
-from_string-function.
-base 1 -> números romanos?
-ref de complejo con agles
Así que aquí está mi solución:
def bn(x,b,ab="0123456789abcdefghijklmnopqrstuvwxyz..."
a = ""
while (x>0):
x,r = divmod(x,n)
a += ab[r]
return a[::-1]
bn(2**100, 36)
Otra solución, funciona con base 2 a 10, necesita modificación para bases más altas:
n2b(10,2) => ''10100''
int(n2b(10,2),2) => 10
Ejemplo:
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]
Otro corto (y más fácil de entender, imo):
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")
Y con el manejo de excepciones adecuado:
def n2b(n, b):
if n == 0:
return 0
d = []
while n:
d.append(int(n % b))
n /= b
return ''''.join(map(str,d[::-1]))
Puede usar baseconv.py: https://github.com/semente/python-baseconv
Uso de muestra:
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
Hay algunos convertidores bultin como por ejemplo baseconv.base2
, baseconv.base16
y baseconv.base64
.
Python no tiene una función incorporada para imprimir un entero en una base arbitraria. Tendrás que escribir el tuyo si quieres.
Si necesita compatibilidad con versiones antiguas de Python, puede usar gmpy (que incluye una función de conversión int-to-string rápida y completamente general, y puede gmpy para versiones antiguas como esta; es posible que deba probar lanzamientos anteriores desde los recientes no han sido probados para versiones venerables de Python y GMP, solo recientes), o, para una menor velocidad pero más conveniente, usan el código de Python, por ejemplo, simplemente:
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)
Sorprendentemente, las personas solo daban soluciones que se convertían en bases pequeñas (más pequeñas que la longitud del alfabeto inglés). No hubo ningún intento de dar una solución que convierta a cualquier base arbitraria de 2 a infinito.
Entonces, aquí hay una solución súper simple:
def numberToBase(n, b):
if n == 0:
return [0]
digits = []
while n:
digits.append(int(n % b))
n /= b # //= for python 3
return digits[::-1]
así que si necesitas convertir un número súper enorme a la base 577
,
numberToBase(67854 ** 15 - 102, 577)
, le dará una solución correcta: [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]
,
Que luego puedes convertir a cualquier base que quieras
Una solución recursiva para los interesados. Por supuesto, esto no funcionará con valores binarios negativos. Debería implementar el complemento de Two.
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()
http://code.activestate.com/recipes/65212/
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
Aquí hay otro del mismo enlace
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
Python doesn''t have a built-in function for printing an integer in an arbitrary base. You''ll have to write your own if you want to.
You could use baseconv.py: 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''
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/
Tenga en cuenta que esto puede conducir a
RuntimeError: maximum recursion depth exceeded in cmp
para enteros muy grandes.
"{0:b}".format(100) # bin: 1100100
"{0:x}".format(100) # hex: 64
"{0:o}".format(100) # oct: 144
>>> 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''
salida:
"1F"
3ewfdnca0n6ld1ggvfgg
salida:
3ewfdnca0n6ld1ggvfgg
para convertir a cualquier base, inversa también es fácil.
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)
explicación
En cualquier base, cada número es igual a a1+a2*base**2+a3*base**3...
La "misión" es encontrar todos a ''s.
Para cada N=1,2,3...
el código está aislando la aN*base**N
por "mouduling" por b para b=base**(N+1)
que corta todas las a ''s mayores que N, y cortando todas las a''s que su serie es más pequeña que N disminuyendo cada vez que el func sea llamado por la aN*base**N
actual aN*base**N
Base% (base-1) == 1 por lo tanto base ** p% (base-1) == 1 y por lo tanto q * base ^ p% (base-1) == q con solo una excepción cuando q = base-1 que devuelve 0. Para arreglar eso en caso de que devuelva 0, el func está comprobando si es 0 desde el principio.
ventajas
en esta muestra hay solo una multiplicación (en lugar de división) y algunos moudulueses que relativamente toman pequeñas cantidades de tiempo.
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
def int_to_str(n, b, symbols=''0123456789abcdefghijklmnopqrstuvwxyz''):
return (int_to_str(n/b, b, symbols) if n >= b else "") + symbols[n%b]
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)