Как преобразовать целое число в любой базе в строку?

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

для очень больших целых чисел.

>>> numpy.base_repr(10, base=3) '101'

рекурсивный

Я бы упростил наиболее проголосовавший ответ:

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)
Другие вопросы по тегам