Frage

ermöglicht Python einfache Erstellung einer ganze Zahl von einer Reihe von einer gegebenen Basis über

int(str, base). 

Ich mag die inverse auszuführen: Schaffung einer Zeichenfolge aus einer ganzen Zahl , das heißt ich möchte eine Funktion int2base(num, base), so dass:

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

Der Funktionsname / Argument ist, um unwichtig.

Für eine beliebige Anzahl x und Basis b dass int() akzeptiert.

Dies ist eine einfache Funktion zu schreiben: in der Tat ist es einfacher, als es in dieser Frage zu beschreiben. Aber ich fühle mich wie ich etwas fehlen muss.

Ich weiß um die Funktionen bin, oct, hex, aber ich kann sie nicht für ein paar Gründe verwenden:

  • Diese Funktionen sind auf ältere Versionen von Python nicht zur Verfügung, mit denen ich brauche die Kompatibilität mit (2.2)

  • Ich mag eine allgemeine Lösung, die die gleiche Art und Weise für unterschiedliche Basen genannt werden kann

  • Ich mag andere Basen als 2, 8, 16

  • ermöglichen

Related

War es hilfreich?

Lösung

Wenn Sie die Kompatibilität mit alten Versionen von Python benötigen, können Sie entweder gmpy (was nicht enthalten ein schnell, ganz allgemein int-to-String-Umwandlungsfunktion, und für solche alten Versionen gebaut werden können - Sie ältere Versionen versuchen müssen, können sich die jüngeren nicht für ehrwürdige Python und GMP Mitteilungen, nur etwas jüngeren) getestet wurde, oder, für weniger Geschwindigkeit, aber mehr Komfort, verwendet Python-Code - zB am einfachsten:

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)

Andere Tipps

Überraschenderweise Menschen gaben nur Lösungen, die Konvertiten zu kleinen Basen (kleiner als die Länge des englischen Alphabets). Es gab keinen Versuch, eine Lösung, die Konvertiten zu jeder beliebigen Basis von 2 bis unendlich zu geben.

So, hier ist eine super einfache Lösung:

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

Wenn Sie also einige super große Zahl an der Basis 577 konvertieren müssen,

numberToBase(67854 ** 15 - 102, 577), werden Sie eine richtige Lösung: [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],

, die Sie später auf jede Basis konvertieren können Sie

wollen
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/

Bitte beachten Sie, dass dies zu

führen
RuntimeError: maximum recursion depth exceeded in cmp

für sehr große Zahlen.

"{0:b}".format(100) # bin: 1100100
"{0:x}".format(100) # hex: 64
"{0:o}".format(100) # oct: 144

Große Antworten! Ich denke, die Antwort auf meine Frage „nein“ war ich nicht einige offensichtliche Lösung fehlt. Hier ist die Funktion, die ich, dass kondensiert die guten Ideen in den Antworten zum Ausdruck verwendet werde.

  • erlauben Anrufer bereitgestellte Zuordnung von Zeichen (erlaubt base64 kodieren)
  • prüft für negative und Null
  • Karten komplexe Zahlen in Tupel von 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

Python hat keine integrierte Funktion zum Drucken einer ganzen Zahl in einer beliebigen Basis. Sie werden Ihre eigenen schreiben, wenn Sie wollen.

Sie baseconv.py von meinem Projekt verwenden: https://github.com/semente/python-baseconv

Verwendungsbeispiel:

>>> 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'

Es gibt einige bultin Wandler wie zum Beispiel baseconv.base2, baseconv.base16 und baseconv.base64.

rekursive

Ich würde simplify meisten Stimmen Antwort :

BS="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
def to_base(n, b): 
    return "0" if not n else to_base(n//b, b).lstrip("0") + BS[n%b]

Mit dem gleichen Rat für RuntimeError: maximum recursion depth exceeded in cmp auf sehr großen Zahlen und negative Zahlen. (Sie könnten verwenden sys.setrecursionlimit(new_limit) )

Iterative

vermeiden Rekursion Probleme :

BS="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
def to_base(s, b):
    res = ""
    while s:
        res+=BS[s%b]
        s//= b
    return res[::-1] or "0"

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

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

Hier ist ein weitere aus dem gleichen 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

Ich habe ein Pip-Paket für diesen.

Ich empfehle Sie verwenden meine bases.py https://github.com/kamijoutouma/bases.py die von bases.js inspiriert

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

siehe https://github.com/kamijoutouma/bases.py#known -basesalphabets für das, was Basen sind verwendbar

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

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)

Ausgabe:

  

"1F"

>>> 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'

Eine rekursive Lösung für die Interessenten. Natürlich wird dies nicht mit negativen binären Werten arbeiten. Sie müßten Zweierkomplement.

implementieren
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 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()

Erklärung

In jeder Basis jede Zahl ist gleich die „Mission“ a1+a2*base**2+a3*base**3... ist alles ein s‘zu finden.

everyN=1,2,3... der Code Isolieren des aN*base**N durch „mouduling“ von b für b=base**(N+1) die alle eine Scheibe ist größer als N, und Aufschneiden alle A 's, dass ihre Serien kleiner als N ist, durch Vermindern eines jedes Mal die FUNC ist von dem aktuellen aN*base**N genannt.

Basis% (Basis-1) == 1 dafür Basis ** p% (Basis-1) == 1 und dafür q * Grund ^ p% (Basis-1) == q mit nur einer Ausnahme, wenn q = Basis-1, die 0 zurückgibt. Um dies zu beheben, dass im Fall gibt es 0 die func prüft es 0 von beggining.


Vorteile

In diesem Beispiel gibt nur einen Multiplikationen (statt Teilung) und einige moudulueses, die relativ geringe Mengen an Zeit in Anspruch nimmt.

num = input("number")
power = 0
num = int(num)
while num > 10:
    num = num / 10
    power += 1

print(str(round(num, 2)) + "^" + str(power))
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 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)

Ein weiterer kurzer (und leichter zu verstehen imo):

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

Und mit dem richtigen Ausnahmebehandlung:

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")

Eine andere Lösung, arbeitet mit Base 2 bis 10, muss Modifikation für höhere Basen:

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]))

Beispiel:

n2b(10,2) => '10100'
int(n2b(10,2),2) => 10

Hier ist eine rekursive Version, die Griffe ganze Zahlen und benutzerdefinierte Ziffern signiert.

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]

Strings sind nicht die einzige Wahl Zahlen für die Darstellung: Sie erhalten eine Liste von ganzen Zahlen können Sie die Reihenfolge der einzelnen Ziffern repräsentieren. Diese können leicht in einen String umgewandelt werden.

Keine der Antworten ablehnen Basis <2; und die meisten werden nur sehr langsam laufen oder Absturz mit Stack-Überlauf für sehr groß Zahlen (zB 56789 ** 43210). Um solche Fehler zu vermeiden, reduzieren schnell wie folgt aus:

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 ist n_to_base vergleichbar mit str für eine große Anzahl (ca. 0,3 s auf meinem Rechner), aber wenn man gegen hex vergleichen Sie werden überrascht sein (etwa 0,3 ms auf meinem Rechner oder 1000x schneller). Der Grund ist, weil die große ganze Zahl im Speicher in der Basis 256 (Bytes) gespeichert ist. Jedes Byte kann einfach auf einen zweistelligen Hex-String umgewandelt werden. Diese Ausrichtung geschieht nur für Basen, die Zweierpotenzen sind, weshalb es spezielle Fälle für 2,8, und 16 (und base64, ascii, utf16, UTF32).

Betrachten Sie die letzte Ziffer einer Dezimalstring. Wie sieht es mit der Sequenz von Bytes beziehen, die seine ganzen Zahl bildet? Lassen Sie uns beschriften die Bytes s[i] mit s[0] das am wenigsten signifikante (Little Endian) zu sein. Dann ist die letzte Ziffer sum([s[i]*(256**i) % 10 for i in range(n)]). Nun, es kommt vor, dass 256 ** i endet mit einem 6 für i> 0 (6 * 6 = 36), so dass letzte Ziffer (s[0]*5 + sum(s)*6)%10 ist. siehe Von diesem können Sie, dass die letzte Ziffer ist abhängig von der Summe aller Bytes. Diese nicht-lokale Eigenschaft ist, was zu dezimal Konvertierung macht härter.

def baseConverter(x, b):
    s = ""
    d = string.printable.upper()
    while x > 0:
        s += d[x%b]
        x = x / b
    return s[::-1]

Ich habe keinen Wandler Schwimmer hier gesehen. Und ich vermisste die für immer drei Ziffern zu gruppieren.

TODO:

-Zahlen in wissenschaftlichen Ausdruck (n.nnnnnn*10**(exp) - die '10' ist self.baseDigits[1::-1]/self.to_string(len (self.baseDigits))

-from_string-Funktion.

-Basis 1 -> römische Zahlen

-repr komplexer mit Agles

So, hier ist meine Lösung:

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)
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)

Ausgabe:

3ewfdnca0n6ld1ggvfgg

auf jede Basis zu konvertieren, invers ist zu einfach.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top