Wie konvertiere ich eine Ganzzahl in eine Zeichenfolge in einer beliebigen Basis?

202

Python ermöglicht die einfache Erstellung einer Ganzzahl aus einer Zeichenfolge einer bestimmten Basis über

int(str, base). 

Ich möchte das Umgekehrte ausführen: Erstellen einer Zeichenfolge aus einer Ganzzahl , dh ich möchte eine Funktion int2base(num, base), z.

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

Der Funktionsname / die Argumentreihenfolge ist unwichtig.

Für jede Zahl xund Basis b, int()die akzeptiert wird.

Dies ist eine einfach zu schreibende Funktion: Tatsächlich ist es einfacher, als sie in dieser Frage zu beschreiben. Ich habe jedoch das Gefühl, dass mir etwas fehlen muss.

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

  • Diese Funktionen sind in älteren Versionen von Python nicht verfügbar, mit denen ich kompatibel sein muss mit (2.2)

  • Ich möchte eine allgemeine Lösung, die für verschiedene Basen gleich bezeichnet werden kann

  • Ich möchte andere Basen als 2, 8, 16 zulassen

verbunden

Mark Borgerding
quelle
5
Überraschenderweise gab niemand eine Lösung an, die mit einer beliebigen großen Basis funktioniert (1023). Wenn Sie es brauchen, überprüfen Sie meine Lösung, die für jede Basis (2 bis inf) stackoverflow.com/a/28666223/1090562
Salvador Dali

Antworten:

98

Wenn Sie Kompatibilität mit alten Versionen von Python benötigen, können Sie entweder gmpy verwenden (das eine schnelle, vollständig allgemeine Konvertierungsfunktion für Zeichenfolgen enthält und für solche alten Versionen erstellt werden kann). Möglicherweise müssen Sie seitdem ältere Versionen ausprobieren Die jüngsten Versionen wurden nicht auf ehrwürdige Python- und GMP-Versionen getestet, sondern nur auf etwas neueren Versionen. Für weniger Geschwindigkeit, aber mehr Komfort verwenden Sie Python-Code - z. B. 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)
Alex Martelli
quelle
8
Nur in (gmpy2) scheint der Funk, von dem Alex spricht, zu sein gmpy2.digits(x, base).
mlvljr
2
Ich wurde darauf aufmerksam gemacht, dass einige Fälle eine Basis> 36 benötigen und daher Ausgrabungen sein solltendigs = string.digits + string.lowercase + string.uppercase
Paul
4
(oder string.digits + string.letters)
Kojiro
3
Irgendeine Idee, warum die Konvertierung von Basis-N-zu-Zeichenfolge in Python nicht standardmäßig enthalten ist? (Es ist in Javascript.) Ja, wir können alle unsere eigene Implementierung schreiben, aber ich habe auf dieser Site und anderswo gesucht, und viele von ihnen haben Fehler. Es ist besser, eine getestete, seriöse Version in der Kerndistribution zu haben.
Jason S
4
@ lordscales91 Sie können auch verwenden, x //= basewas sich wie /=in Python 2 verhält, wenn Sie die Dezimalstelle löschen . Diese Antwort sollte einen Haftungsausschluss enthalten, der für Python 2 gilt.
Noumenon
100

Überraschenderweise gaben die Leute nur Lösungen an, die sich in kleine Basen umwandeln lassen (kleiner als die Länge des englischen Alphabets). Es gab keinen Versuch, eine Lösung zu finden, die sich in eine beliebige Base von 2 bis unendlich umwandelt.

Also 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 eine super große Zahl in die Basis konvertieren müssen 577,

numberToBase(67854 ** 15 - 102, 577), gibt Ihnen eine korrekte 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],

Was Sie später in eine beliebige Basis konvertieren können

Salvador Dali
quelle
Im College habe ich eine Funktion entwickelt, mit der Basen unter 20 in Standardnotation und Basen unter 20 in "durch Doppelpunkte getrennte Dezimalstellen" formatiert wurden. Zum Beispiel int(4545,16)gab "11c1" und int(4545,60)gab "1:15:45". Somit hatte die Funktion eine dreifache Aufgabe: Konvertieren in Dezimal-, Computer- und Zeitstempelformate.
Peter Raynham
1
Was ist die Umkehrfunktion für diese Methode?
Sohrab T
Dies beantwortet die gestellte Frage aus drei Gründen nicht: 1: Die Frage, die für eine vorhandene Bibliotheksfunktion gestellt wurde, ist keine Implementierung. 2: Die Frage, die für eine Zeichenfolge gestellt wurde. Dies erzeugt eine Liste. 3: Dies ist keine Umkehrung für int (str, Basis) eingebaut.
Plugwash
@plugwash 1) Irgendwann werden Sie feststellen, dass es manchmal keine eingebaute Bibliotheksfunktion gibt, um die gewünschten Dinge zu tun, sodass Sie Ihre eigenen schreiben müssen. Wenn Sie nicht einverstanden sind, veröffentlichen Sie Ihre eigene Lösung mit einer integrierten Funktion, die eine Basis-10-Zahl in Basis-577 konvertieren kann. 2) Dies liegt daran, dass Sie nicht verstehen, was eine Zahl in einer Basis bedeutet. 3) Ich ermutige Sie, ein wenig darüber nachzudenken, warum die Basis in Ihrer Methode nur für n <= 36 funktioniert. Wenn Sie fertig sind, wird es offensichtlich sein, warum meine Funktion eine Liste zurückgibt und die Signatur hat, die sie hat.
Salvador Dali
1
Dies funktioniert nicht für negative Zahlen, und ich bin mir nicht sicher, wie ich es zum Laufen bringen soll, ohne es grundlegend zu ändern. Vielleicht durch Hinzufügen eines Vorzeichenbits, 1 oder -1, oben auf digits?
Wjandrea
89
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 dazu führen kann

RuntimeError: maximum recursion depth exceeded in cmp

für sehr große ganze Zahlen.

Quallenbaum
quelle
5
Elegant in seiner Kürze. Es scheint unter Python 2.2.3 für nicht negative ganze Zahlen zu funktionieren. Eine negative Zahl wiederholt sich unendlich.
Mark Borgerding
+1 nützlich; Es wurde ein Problem behoben, bei dem Ziffern nicht mit '0'
begannen
4
Dies schlägt lautlos fehl (a) wenn die Basis> len(numerals)ist und (b) num % bglücklicherweise <ist len(numerals). Obwohl die numeralsZeichenfolge nur 36 Zeichen lang ist, gibt baseN (60, 40) zurück, '1k'während baseN (79, 40) ein erhöht IndexError. Beide sollten einen Fehler auslösen. Der Code sollte überarbeitet werden, um einen Fehler auszulösen, wenn not 2 <= base <= len(numerals).
Chris Johnson
3
@osa, mein Punkt ist, dass der geschriebene Code auf sehr schlechte Weise fehlschlägt (stillschweigend, irreführende Antwort) und leicht behoben werden kann. Wenn Sie sagen, dass es keinen Fehler geben würde, wenn Sie im Voraus sicher wüssten, dass bdies nicht len(numerals)viel Glück für Sie bedeuten würde.
Chris Johnson
1
Die Verwendung von Kurzschlüssen hier erscheint unnötig verwirrend ... warum nicht einfach eine if-Anweisung verwenden ... die Zeile return numerals[0] if num == 0 else baseN(num // b, b, numerals).lstrip(numerals[0]) + numerals[num % b]ist genauso kurz.
Ian Hincks
83
"{0:b}".format(100) # bin: 1100100
"{0:x}".format(100) # hex: 64
"{0:o}".format(100) # oct: 144
Rost
quelle
46
Aber nur diese drei Basen?
Thomas Ahle
3
Ja, leider können Sie keine benutzerdefinierte int-Basis angeben. Weitere Informationen finden Sie hier: docs.python.org/library/string.html#formatstrings
Rost
3
Das 0ist unnötig. Hier ist die Python 2-Dokumentation: docs.python.org/2/library/string.html#format-string-syntax
Evgeni Sergeev
7
Sie können die gleichen Ergebnisse mit erreichen hex(100)[2:], oct(100)[2:]und bin(100)[2:].
Sassan
2
@ EvgeniSergeev: Es ist nur auf 2.7 / 3.1 + unnötig. In 2.6 ist die explizite Position (oder der Name) erforderlich.
ShadowRanger
21

Tolle Antworten! Ich denke, die Antwort auf meine Frage war "nein". Mir fehlte keine offensichtliche Lösung. Hier ist die Funktion, die ich verwenden werde, um die guten Ideen, die in den Antworten zum Ausdruck kommen, zu verdichten.

  • vom Anrufer bereitgestellte Zuordnung von Zeichen zulassen (ermöglicht die Base64-Codierung)
  • prüft auf negativ und null
  • ordnet komplexe Zahlen Tupeln von Zeichenfolgen zu


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

Mark Borgerding
quelle
4
Wie konvertieren Sie die base64-Ausgabe unserer Funktion zurück in eine Ganzzahl?
Detly
16

Rekursiv

Ich würde die am häufigsten gewählte Antwort auf Folgendes vereinfachen :

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 cmpsehr große ganze Zahlen und negative Zahlen. (Sie könnten verwenden sys.setrecursionlimit(new_limit))

Iterativ

So vermeiden Sie Rekursionsprobleme :

BS="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
def to_base(s, b):
    res = ""
    while s:
        res+=BS[s%b]
        s//= b
    return res[::-1] or "0"
MM
quelle
2
Wunderschön renoviert und ohne Bibliothek.
Giampaolo Ferradini
Sollte dann nicht die Stoppbedingung sein return BS[0] if not n? Nur für den Fall, dass Sie ausgefallene Ziffern verwenden möchten, wie ich :)
Arnaud P
@ArnaudP stimmte zu. Dieser funktioniert für mich:return BS[n] if n < b else to_base(n // b) + BN[n % b]
Jens
15

Python verfügt nicht über eine integrierte Funktion zum Drucken einer Ganzzahl in einer beliebigen Basis. Sie müssen Ihre eigenen schreiben, wenn Sie wollen.

Mike Graham
quelle
13

Sie können baseconv.pyaus meinem Projekt verwenden: https://github.com/semente/python-baseconv

Beispielnutzung:

>>> 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.base16und baseconv.base64.

semente
quelle
12

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

V. Ayrat
quelle
Schöne Lösung. In meinem Fall habe ich es vermieden, mich clacwegen Bedenken hinsichtlich der Ladezeit einzumischen . Das Vorladen von numpy verdreifacht die Laufzeit der einfachen Expressionsbewertung in clac um mehr als das Dreifache: z. B. clac 1+1 ging es von etwa 40 ms auf 140 ms.
Mark Borgerding
1
Beachten Sie, dass numpy.base_repr()die Basis ein Limit von 36 hat. Ansonsten wirft es aValueError
sbdchd
Das entspricht der Einschränkung der eingebauten "int" -Funktion. Bei größeren Basen muss entschieden werden, was zu tun ist, wenn die Buchstaben ausgehen.
Plugwash
4

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 noch einer vom selben 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
John La Rooy
quelle
base10toN berücksichtigt nicht den Fall von num == 0.
Craeft
3

Ich habe ein Pip-Paket dafür gemacht.

Ich empfehle Ihnen, meine base.py https://github.com/kamijoutouma/bases.py zu verwenden, die von base.js inspiriert wurde

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

Informationen zu den verwendbaren Basen finden Sie unter https://github.com/kamijoutouma/bases.py#known-basesalphabets

BEARBEITEN: pip link https://pypi.python.org/pypi/bases.py/0.2.2

Belldandu
quelle
Dies funktioniert wie ein Zauber für die angegebenen bekannten Basen .
Agi Hammerthief
Dies ist bei weitem die beste Antwort! Und danke für die Pip-Verpackung!
27.
3
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"

Mukundan
quelle
other-baseist das gleiche wie other - base, also sollten Sie verwendenother_base
mbomb007
Dies funktioniert auch nicht richtig, wenn decimalNull ist.
mbomb007
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'
SilentGhost
quelle
1

Eine rekursive Lösung für Interessierte. Dies funktioniert natürlich nicht mit negativen Binärwerten. Sie müssten Two's Complement 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
Mr. Polywhirl
quelle
1
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()

Erläuterung

In jeder Basis ist jede Zahl gleich a1+a2*base**2+a3*base**3...Die "Mission" ist es, alle a zu finden.

Für jeden N=1,2,3...isoliert der Code das aN*base**Ndurch "Mouduling" durch b, für b=base**(N+1) das alle a größer als N sind, und schneidet alle a, deren Seriennummer kleiner als N ist, durch Verringern von a jedes Mal, wenn die Funktion vom Strom aufgerufen wird aN*base**N.

Basis% (Basis-1) == 1 dafür Basis ** p% (Basis-1) == 1 und dafür q * Basis ^ p% (Basis-1) == q mit nur einer Ausnahme, wenn q = Basis-1 Dies gibt 0 zurück. Um dies zu beheben, falls es 0 zurückgibt, prüft die Funktion von Anfang an, ob es 0 ist.


Vorteile

In dieser Stichprobe gibt es nur eine Multiplikation (anstelle einer Division) und einige Moudulues, was relativ wenig Zeit in Anspruch nimmt.

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

print(str(round(num, 2)) + "^" + str(power))
Casey Howard
quelle
Bitte fügen Sie einige kurze Informationen hinzu, die Sie speziell
initiiert haben
Dies könnte zwar die Frage des Autors beantworten, es fehlen jedoch einige erklärende Wörter und / oder Links zur Dokumentation. Rohcode-Schnipsel sind ohne einige Ausdrücke nicht sehr hilfreich. Möglicherweise ist es auch sehr hilfreich , eine gute Antwort zu schreiben . Bitte bearbeiten Sie Ihre Antwort.
Gelb
1
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]   
montaqami
quelle
In dieser Funktion können Sie einfach eine beliebige Dezimalzahl in Ihre Lieblingsbasis konvertieren.
Montanaqami
Sie müssen Ihre eigene Antwort nicht kommentieren, sondern können sie nur bearbeiten, um eine Erklärung hinzuzufügen.
Pochmurnik
1

Hier ist ein Beispiel, wie eine Zahl einer beliebigen Basis in eine andere Basis konvertiert wird.

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!!!")
Vlad Bezden
quelle
0
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)
nameisnotphil
quelle
0

Noch eine kurze (und imo leichter zu verstehen):

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 der 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")
Ariel
quelle
0

Eine andere Lösung, die mit Basis 2 bis 10 arbeitet, muss für höhere Basen geändert werden:

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
Stanislav
quelle
0

Hier ist eine rekursive Version, die vorzeichenbehaftete Ganzzahlen und benutzerdefinierte Ziffern verarbeitet.

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]
Antoine Pinsard
quelle
0

Zeichenfolgen sind nicht die einzige Wahl für die Darstellung von Zahlen: Sie können eine Liste von Ganzzahlen verwenden, um die Reihenfolge jeder Ziffer darzustellen. Diese können leicht in eine Zeichenfolge konvertiert werden.

Keine der Antworten lehnt Basis <2 ab; und die meisten laufen sehr langsam oder stürzen bei sehr großen Zahlen mit Stapelüberläufen ab (z. B. 56789 ** 43210). Um solche Fehler zu vermeiden, reduzieren Sie diese schnell wie folgt:

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 n_to_baseist vergleichbar mit strgroßen Zahlen (ca. 0,3 s auf meinem Computer), aber wenn Sie es mit anderen vergleichen, werden hexSie überrascht sein (ca. 0,3 ms auf meinem Computer oder 1000x schneller). Der Grund ist, dass die große Ganzzahl im Speicher in der Basis 256 (Bytes) gespeichert ist. Jedes Byte kann einfach in eine zweistellige Hex-Zeichenfolge konvertiert werden. Diese Ausrichtung erfolgt nur für Basen mit Zweierpotenzen, weshalb es Sonderfälle für 2,8 und 16 gibt (und base64, ascii, utf16, utf32).

Betrachten Sie die letzte Ziffer einer Dezimalzeichenfolge. In welcher Beziehung steht es zu der Folge von Bytes, die seine ganze Zahl bilden? Lassen Sie uns beschriften Sie die Bytes s[i]mit s[0]ist das am wenigsten signifikante (Little Endian). Dann ist die letzte Ziffer sum([s[i]*(256**i) % 10 for i in range(n)]). Nun, es kommt vor, dass 256 ** i mit einer 6 für i> 0 endet (6 * 6 = 36), so dass die letzte Ziffer ist (s[0]*5 + sum(s)*6)%10. Daraus können Sie ersehen, dass die letzte Ziffer von der Summe aller Bytes abhängt. Diese nichtlokale Eigenschaft erschwert die Konvertierung in Dezimalzahlen.

Colski
quelle
0
def baseConverter(x, b):
    s = ""
    d = string.printable.upper()
    while x > 0:
        s += d[x%b]
        x = x / b
    return s[::-1]
gjivanya
quelle
Für Python3 führt Ihr Code Folgendes aus: baseConverter (0, 26) -> '' baseConverter (1, 26) -> '0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -> 1 BaseConverter (3, 26) -> 3 BaseConverter (5, 26) -> 5 BaseConverter (26, 26) -> 10 BaseConverter (32, 26) -> 16
Drachenfels
0

Nun, ich persönlich benutze diese von mir geschriebene Funktion

import string

def to_base(value, base, digits=string.digits+string.ascii_letters):    # converts decimal to base n

    digits_slice = digits[0:base]

    temporary_var = value
    data = [temporary_var]

    while True:
        temporary_var = temporary_var // base
        data.append(temporary_var)
        if temporary_var < base:
            break

    result = ''
    for each_data in data:
        result += digits_slice[each_data % base]
    result = result[::-1]

    return result

So können Sie es verwenden

print(to_base(7, base=2))

Ausgabe: "111"

print(to_base(23, base=3))

Ausgabe: "212"

Bitte zögern Sie nicht, Verbesserungen in meinem Code vorzuschlagen.

Artaza Sameen
quelle
0
def base_conversion(num, base):
    digits = []
    while num > 0:
        num, remainder = divmod(num, base)
        digits.append(remainder)
    return digits[::-1]
hxuanhung
quelle
0

Dies ist eine alte Frage, aber ich dachte, ich würde meine Meinung dazu teilen, da ich der Meinung bin, dass es etwas einfacher ist als andere Antworten (gut für Basen von 2 bis 36):

def intStr(n,base=10):
    if n < 0   : return "-" + intStr(-n,base)         # handle negatives
    if n < base: return chr([48,55][n>9] + n)         # 48 => "0"..., 65 => "A"...
    return intStr(n//base,base) + intStr(n%base,base) # recurse for multiple digits
Alain T.
quelle
-1

Ich habe hier keine Schwimmerkonverter gesehen. Und ich habe die Gruppierung immer dreistellig verpasst.

MACHEN:

-Zahlen im wissenschaftlichen Ausdruck (n.nnnnnn*10**(exp)- das '10'istself.baseDigits[1::-1]/self.to_string(len (self.baseDigits))

-from_string-Funktion.

-Basis 1 -> römische Zahlen?

-repr von Komplex mit Agles

Also 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)
cmdLP
quelle
-2
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

In eine beliebige Basis umzuwandeln, ist auch invers einfach.

Rogério Duarte
quelle
Verstanden NameError: global name 'n' is not defined. Soll divmod(x, n)sein divmod(x, b)?
Wjandrea