Как преобразовать целое число в любой базе в строку?
Python позволяет легко создавать целое число из строки заданной базы с помощью
int(str, base).
Я хочу выполнить обратное: создание строки из целого числа, т.е. я хочу некоторую функцию int2base(num, base)
такой, что:
int(int2base(x, b), b) == x
Порядок имени / аргумента функции не имеет значения.
Для любого номера x
и база b
тот int()
приму.
Это простая функция для написания: на самом деле это проще, чем описать ее в этом вопросе. Однако я чувствую, что, должно быть, чего-то не хватает.
Я знаю о функциях bin
, oct
, hex
, но я не могу использовать их по нескольким причинам:
Эти функции недоступны в старых версиях Python, с которыми мне нужна совместимость с (2.2)
Я хочу общее решение, которое можно назвать одинаково для разных баз
Я хочу разрешить базы, отличные от 2, 8, 16
связанные с
40 ответов
Если вам нужна совместимость с древними версиями Python, вы можете использовать gmpy (который включает в себя быструю, полностью общую функцию преобразования в строку и может быть построен для таких древних версий), возможно, вам придется попробовать более старые выпуски, так как последние не были протестированы для почтенных выпусков Python и GMP, только несколько последних), или, для меньшей скорости, но большего удобства, использовали код Python - например, наиболее просто:
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)
Удивительно, но люди давали только решения, которые конвертировались в маленькие базы (меньше длины английского алфавита). Не было попыток дать решение, которое преобразуется в любую произвольную базу от 2 до бесконечности.
Итак, вот супер простое решение:
def numberToBase(n, b):
if n == 0:
return [0]
digits = []
while n:
digits.append(int(n % b))
n //= b
return digits[::-1]
так что если вам нужно конвертировать какое-то супер огромное число в базу 577
,
numberToBase(67854 ** 15 - 102, 577)
, даст вам правильное решение:[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]
,
Который вы можете позже преобразовать в любую базу, которую вы хотите
"{0:b}".format(100) # bin: 1100100
"{0:x}".format(100) # hex: 64
"{0:o}".format(100) # oct: 144
def baseN(num,b,numerals="0123456789abcdefghijklmnopqrstuvwxyz"):
return ((num == 0) and numerals[0]) or (baseN(num // b, b, numerals).lstrip(numerals[0]) + numerals[num % b])
ссылка: http://code.activestate.com/recipes/65212/
Пожалуйста, имейте в виду, что это может привести к
RuntimeError: maximum recursion depth exceeded in cmp
для очень больших целых чисел.
рекурсивный
Я бы упростил наиболее проголосовавший ответ:
BS="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
def to_base(n, b):
return "0" if not n else to_base(n//b, b).lstrip("0") + BS[n%b]
С тем же советом для RuntimeError: maximum recursion depth exceeded in cmp
на очень большие целые и отрицательные числа. (Вы могли бы использовать sys.setrecursionlimit(new_limit)
)
итеративный
Чтобы избежать проблем с рекурсией:
BS="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
def to_base(s, b):
res = ""
while s:
res+=BS[s%b]
s//= b
return res[::-1] or "0"
Отличные ответы! Я думаю, что ответом на мой вопрос было "нет", я не упустил какое-то очевидное решение. Вот функция, которую я буду использовать, которая объединяет хорошие идеи, выраженные в ответах.
- разрешить сопоставление символов, предоставляемое вызывающим абонентом (позволяет кодировать base64)
- проверяет на отрицание и ноль
- отображает комплексные числа в цепочки строк
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 нет встроенной функции для печати целого числа в произвольной базе. Вы должны написать свой собственный, если хотите.
Вы могли бы использовать baseconv.py
из моего проекта: https://github.com/semente/python-baseconv
Пример использования:
>>> 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'
Есть некоторые конвертеры bultin как например baseconv.base2
, baseconv.base16
а также baseconv.base64
,
def base_conversion(num, base):
digits = []
while num > 0:
num, remainder = divmod(num, base)
digits.append(remainder)
return digits[::-1]
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)
выход:
"1F"
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
Вот еще один по той же ссылке
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
Я сделал пакет для этого.
Я рекомендую вам использовать мой Base.py https://github.com/kamijoutouma/bases.py который был вдохновлен Base.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
обратитесь к https://github.com/kamijoutouma/bases.py, чтобы узнать, какие базы можно использовать
РЕДАКТИРОВАТЬ: pip-ссылка https://pypi.python.org/pypi/bases.py/0.2.2
Хотя в настоящее время лучший ответ , безусловно, является отличным решением, остается больше возможностей для настройки, которые могут понравиться пользователям.
Basencode добавляет некоторые из этих функций, включая преобразование чисел с плавающей запятой, изменение цифр (в связанном ответе можно использовать только числа).
Вот возможный вариант использования:
>>> 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'
Как бы вы добавили любые базы, которые вы хотите? Позвольте мне воспроизвести пример ответа, за который в настоящее время проголосовали больше всего:digits
Параметр позволяет вам переопределить цифры по умолчанию от 2 до 64 и предоставить цифры для любого основания выше этого. mode
Параметр определяет, как значение представления будет определять, как (список или строка) будет возвращен ответ.
>>> 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']
Операции можно делать:Number
класс возвращает экземплярbasencode.Integer
если предоставленное число является целым числом, иначе он возвращает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'
Отказ от ответственности: этот проект находится на активном обслуживании, и я являюсь его участником.
>>> 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'
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()
объяснение
В любой базе каждое число равно a1+a2*base**2+a3*base**3...
"Миссия" - найти все.
Для каждогоN=1,2,3...
код изолирует aN*base**N
"mouduling" по б для b=base**(N+1)
которые нарезают все a больше N, и нарезают все a, что их серийный номер меньше N, уменьшая при каждом вызове функции текущим aN*base**N
,
Base%(base-1)==1 для этого base**p%(base-1)==1 и для этого q*base^p%(base-1)==q только с одним исключением, когда q=base-1 который возвращает 0. Чтобы исправить это в случае, если он возвращает 0, функция проверяет, равен ли он 0 с самого начала.
преимущества
в этом примере есть только одно умножение (вместо деления) и несколько moudulueses, что относительно занимает небольшое количество времени.
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]
Рекурсивное решение для тех, кто заинтересован. Конечно, это не будет работать с отрицательными двоичными значениями. Вам нужно будет реализовать Дополнение Два.
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
num = input("number")
power = 0
num = int(num)
while num > 10:
num = num / 10
power += 1
print(str(round(num, 2)) + "^" + str(power))
Вот пример того, как преобразовать число из любой базы в другую базу.
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!!!")
Другое решение, работающее с базами от 2 до 10, требует модификации для более высоких баз:
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]))
Пример:
n2b(10,2) => '10100'
int(n2b(10,2),2) => 10
Вот код, который я написал, чтобы помочь тем, кто хотел быстро вычислить значение по основанию 3 реального огромного целого числа . Оказывается, способ сделать это — создать функцию, работающую с любой базой, и заставить ее рекурсивно вызывать себя. Это использует несколько свойств:
- Python может работать с целыми числами неограниченного размера и выполнять над ними все обычные арифметические операции.
- Преобразовать из в легко, поскольку каждая цифра в
base**2
превращается в две цифрыbase
используя простое деление и остаток. - Если основание больше, чем число, которое вы пытаетесь преобразовать, ответ тривиален: число представляет собой одну цифру.
def number_to_base(n, base):
if n < base:
return [n]
else:
digits = [d for x in number_to_base(n, base*base) for d in divmod(x, base)]
return digits if digits[0] else digits[1:]
Это возвращает список числовых цифр. Чтобы преобразовать его в строку, которую можно интерпретировать с помощьюint(s, base)
довольно просто:
def int2base(x, base, alphabet='0123456789abcdefghijklmnopqrstuvwxyz'):
return ''.join(alphabet[digit] for digit in number_to_base(x, base))
Это обрабатывает только положительные числа, но заставить его обрабатывать отрицательные числа тривиально — я оставляю это в качестве упражнения для читателя.
Эта функция на самом деле быстрее, чем Pythonstr()
функция для основания 10, если число достаточно велико. В моих тестах они были равны примерно 100000 цифр.
Простое базовое преобразование
def int_to_str(x,b):
s=""
while x :
s = str(x%b) + s
x//=b
return s
Пример вывода без 0 по основанию 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)
Я написал эту функцию, которую использую для кодирования в разных базах. Я также предоставил способ сдвинуть результат на величину смещения. Это полезно, если вы хотите кодировать в базы выше 64, но сохраняя отображаемые символы (например, базу 95).
Я также старался не переворачивать выходной «список» и старался минимизировать вычислительные операции. Массив pow(base) вычисляется по запросу и сохраняется для дополнительных вызовов функции.
На выходе получается двоичная строка.
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()
Приведенный ниже код Python преобразует целое число Python в строку в произвольной базе (от 2 до бесконечности) и работает в обоих направлениях. Таким образом, все созданные строки можно преобразовать обратно в целые числа Python, предоставив строку для N вместо целого числа. Код намеренно работает только с положительными числами (на мой взгляд, есть некоторые проблемы с отрицательными значениями и их битовыми представлениями, в которые я не хочу вникать). Просто выберите из этого кода то, что вам нужно, хотите или нравится, или просто получайте удовольствие, изучая доступные варианты. Многое здесь только для того, чтобы задокументировать все различные доступные подходы (например, Oneliner кажется не быстрым, даже если обещают).
Мне нравится предложенный Сальвадором Дали формат бесконечно больших оснований. Хорошее предложение, которое оптически хорошо работает даже для простых двоичных битовых представлений. Обратите внимание, что параметр заполнения width=x в случае строки с форматированием InfiniteBase=True применяется к цифрам, а не ко всему числу. Кажется, что код, обрабатывающий формат чисел в формате InfiniteBase, работает даже немного быстрее, чем другие варианты - еще одна причина для его использования?
Мне не нравится идея использовать Unicode для увеличения количества символов, доступных для цифр, поэтому не ищите его в приведенном ниже коде, потому что его там нет. Вместо этого используйте предложенный формат InfiniteBase или сохраните целые числа в виде байтов для целей сжатия.
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
Эта функция преобразует любое целое число из любой базы в любую базу
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)
Для оснований от 2 до 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
Это мой подход. Сначала преобразование числа, а затем преобразование его в строку.
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)
Скажем, мы хотим преобразовать 14 в основание 2. Мы неоднократно применяем алгоритм деления, пока частное не станет равным 0:
14 = 2 х 7
7 = 2 х 3 + 1
3 = 2 х 1 + 1
1 = 2 х 0 + 1
Двоичное представление - это просто остаток, читаемый снизу вверх. Это можно доказать, расширив
14 = 2 х 7 = 2 х (2 х 3 + 1) = 2 х (2 х (2 х 1 + 1) + 1) = 2 х (2 х (2 х (2 х 0 + 1) + 1) + 1) = 2 ^ 3 + 2 ^ 2 + 2
Код является реализацией описанного выше алгоритма.
def toBaseX(n, X):
strbin = ""
while n != 0:
strbin += str(n % X)
n = n // X
return strbin[::-1]
Я не видел никаких преобразователей поплавка здесь. И я пропустил группировку для всегда трех цифр.
СДЕЛАТЬ:
числа в научном выражении (n.nnnnnn*10**(exp)
- '10'
является self.baseDigits[1::-1]/self.to_string(len (self.baseDigits))
-from_string-функция.
1 -> римские цифры?
-репр комплекс с аглс
Итак, вот мое решение:
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)