Làm thế nào để chuyển đổi một số nguyên thành một chuỗi trong bất kỳ cơ sở?


202

Python cho phép dễ dàng tạo một số nguyên từ một chuỗi của một cơ sở nhất định thông qua

int(str, base). 

Tôi muốn thực hiện nghịch đảo: tạo một chuỗi từ một số nguyên , tức là tôi muốn một số hàm int2base(num, base), chẳng hạn như:

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

Tên hàm / thứ tự đối số là không quan trọng.

Đối với bất kỳ số lượng xvà cơ sở bđó int()sẽ chấp nhận.

Đây là một chức năng dễ viết: thực tế nó dễ hơn mô tả nó trong câu hỏi này. Tuy nhiên, tôi cảm thấy mình phải thiếu thứ gì đó.

Tôi biết về chức năng bin, oct, hex, nhưng tôi không thể sử dụng chúng cho một vài lý do:

  • Các chức năng này không có sẵn trên các phiên bản cũ hơn của Python, mà tôi cần tương thích với (2.2)

  • Tôi muốn một giải pháp chung có thể được gọi là cùng một cách cho các cơ sở khác nhau

  • Tôi muốn cho phép các căn cứ khác ngoài 2, 8, 16

Liên quan


5
Đáng ngạc nhiên là không ai đưa ra một giải pháp hoạt động với cơ sở lớn tùy ý (1023). Nếu bạn cần nó, hãy kiểm tra giải pháp của tôi hoạt động cho mọi cơ sở (2 đến inf) stackoverflow.com/a/28666223/1090562
Salvador Dali

Câu trả lời:


98

Nếu bạn cần khả năng tương thích với các phiên bản Python cổ, bạn có thể sử dụng gmpy (bao gồm chức năng chuyển đổi int-to-string nhanh, hoàn toàn chung và có thể được xây dựng cho các phiên bản cổ như vậy - bạn có thể cần thử các bản phát hành cũ hơn kể từ đó những cái gần đây chưa được thử nghiệm cho các bản phát hành Python và GMP đáng kính, chỉ một số gần đây), hoặc, để có tốc độ thấp hơn nhưng thuận tiện hơn, hãy sử dụng mã Python - ví dụ: đơn giản nhất:

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)

8
Chỉ trong trường hợp (gmpy2), func Alex nói về dường như gmpy2.digits(x, base).
mlvljr

2
Tôi đã nhận thấy rằng một số trường hợp cần một cơ sở> 36 và vì vậy nên đàodigs = string.digits + string.lowercase + string.uppercase
Paul

4
(hoặc string.digits + string.letters)
kojiro

3
Có ai biết tại sao convert-base-N-to-string không được bao gồm trong Python không? (Đó là trong Javascript.) Vâng, tất cả chúng ta đều có thể tự viết triển khai, nhưng tôi đã tìm kiếm trên trang này và các nơi khác, và nhiều trong số chúng có lỗi. Tốt hơn là có một phiên bản thử nghiệm, có uy tín được bao gồm trong phân phối cốt lõi.
Jason S

4
@ lordscales91 Bạn cũng có thể sử dụng x //= basehành vi giống như /=trong Python 2 trong việc bỏ số thập phân. Câu trả lời này phải bao gồm từ chối trách nhiệm dành cho Python 2.
Noumenon

100

Đáng ngạc nhiên, mọi người chỉ đưa ra các giải pháp chuyển đổi sang các cơ sở nhỏ (nhỏ hơn chiều dài của bảng chữ cái tiếng Anh). Không có nỗ lực để đưa ra một giải pháp chuyển đổi sang bất kỳ cơ sở tùy ý nào từ 2 đến vô cùng.

Vì vậy, đây là một giải pháp siêu đơn giản:

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

vì vậy nếu bạn cần chuyển đổi một số siêu lớn sang cơ sở 577,

numberToBase(67854 ** 15 - 102, 577), sẽ cung cấp cho bạn một giải pháp chính xác : [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],

Mà sau này bạn có thể chuyển đổi sang bất kỳ cơ sở nào bạn muốn


Ở trường đại học, tôi đã đưa ra một chức năng định dạng các cơ sở dưới 20 thành ký hiệu chuẩn và các cơ sở 20 trở lên thành 'số thập phân được phân cách bằng dấu hai chấm'. Ví dụ: int(4545,16)đã cho "11c1" và int(4545,60)đưa ra "1:15:45". Do đó, hàm đã thực hiện ba nhiệm vụ: chuyển đổi sang các định dạng thập phân, vi tính và dấu thời gian.
Peter Raynham

1
Hàm nghịch đảo của phương thức này là gì?
Sohrab T

Điều này không trả lời câu hỏi được hỏi vì 3 lý do, 1: câu hỏi yêu cầu chức năng thư viện hiện có không phải là triển khai 2: câu hỏi yêu cầu chuỗi, điều này tạo ra danh sách 3: đây không phải là nghịch đảo cho int (str, cơ sở) dựng sẵn.
cắm vào

@plugwash 1) tại một số thời điểm bạn sẽ nhận thấy rằng đôi khi không có chức năng thư viện dựng sẵn để làm những việc bạn muốn, vì vậy bạn cần phải tự viết. Nếu bạn không đồng ý, hãy đăng giải pháp của riêng bạn với hàm dựng sẵn có thể chuyển đổi số 10 cơ sở thành cơ sở 577. 2) điều này là do thiếu hiểu ý nghĩa của một số trong một số cơ sở. 3) Tôi khuyến khích bạn suy nghĩ một chút tại sao cơ sở trong phương thức của bạn chỉ hoạt động cho n <= 36. Sau khi bạn hoàn thành, rõ ràng tại sao hàm của tôi trả về một danh sách và có chữ ký.
Salvador Dali

1
Điều này không hoạt động đối với các số âm và tôi không chắc làm thế nào để nó hoạt động mà không thay đổi về cơ bản. Có thể bằng cách thêm một bit dấu, 1 hoặc -1, ở đầu 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])

tham chiếu: http://code.activestate.com/recipes/65212/

Xin lưu ý rằng điều này có thể dẫn đến

RuntimeError: maximum recursion depth exceeded in cmp

cho số nguyên rất lớn.


5
Thanh lịch trong sự ngắn gọn của nó. Nó dường như hoạt động theo python 2.2.3 cho các số nguyên không âm. Một số âm vô hạn đệ quy.
Mark Borgerding

+1 hữu ích; đã khắc phục sự cố khi các chữ số không bắt đầu bằng '0'
sehe

4
Điều này thất bại âm thầm (a) khi cơ sở là> len(numerals)và (b) num % blà, may mắn, < len(numerals). ví dụ: mặc dù numeralschuỗi chỉ dài 36 ký tự, baseN (60, 40) trả về '1k'trong khi baseN (79, 40) tăng một IndexError. Cả hai nên đưa ra một số loại lỗi. Mã nên được sửa đổi để đưa ra một lỗi nếu not 2 <= base <= len(numerals).
Chris Johnson

3
@osa, quan điểm của tôi là mã được viết không thành công theo cách rất xấu (âm thầm, đưa ra câu trả lời sai lệch) và có thể được sửa một cách dễ dàng. Nếu bạn đang nói sẽ không có lỗi nếu bạn biết trước, chắc chắn, điều đó bsẽ không vượt quá len(numerals), tốt, chúc may mắn cho bạn.
Chris Johnson

1
Việc sử dụng ngắn mạch ở đây có vẻ khó hiểu ... tại sao không sử dụng câu lệnh if ... dòng return numerals[0] if num == 0 else baseN(num // b, b, numerals).lstrip(numerals[0]) + numerals[num % b]này chỉ ngắn gọn.
Ian Hincks

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

46
Nhưng nó chỉ làm ba căn cứ?
Thomas Ahle

3
Có, thật không may, bạn không thể chỉ định cơ sở int tùy chỉnh. Thêm thông tin ở đây: docs.python.org/l Library / chuỗi.html
Rost

3
Điều 0không cần thiết. Đây là tài liệu về Python 2: docs.python.org/2/l Library / chuỗi.html
Evgeni Sergeev

7
Bạn có thể đạt được kết quả tương tự với hex(100)[2:], oct(100)[2:]bin(100)[2:].
Sassan

2
@EvgeniSergeev: Nó không cần thiết trên 2.7 / 3.1 +. Trên 2.6, vị trí rõ ràng (hoặc tên) là bắt buộc.
ShadowRanger

21

Câu trả lời tuyệt vời! Tôi đoán câu trả lời cho câu hỏi của tôi là "không" Tôi không thiếu một số giải pháp rõ ràng. Đây là chức năng tôi sẽ sử dụng để cô đọng những ý tưởng hay được thể hiện trong các câu trả lời.

  • cho phép ánh xạ các ký tự do người gọi cung cấp (cho phép mã hóa base64)
  • kiểm tra âm và không
  • ánh xạ các số phức thành các chuỗi


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


4
Làm thế nào để bạn chuyển đổi đầu ra base64 của hàm của chúng tôi thành một số nguyên?
gièm pha

16

Đệ quy

Tôi sẽ đơn giản hóa các câu trả lời đã bỏ phiếu nhất để:

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

Với cùng một lời khuyên cho RuntimeError: maximum recursion depth exceeded in cmpsố nguyên rất lớn và số âm. (Bạn có thể sử dụng sys.setrecursionlimit(new_limit))

Lặp đi lặp lại

Để tránh các vấn đề đệ quy :

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

2
Đẹp tái cấu trúc, và không có thư viện.
Giampaolo Ferradini

Không phải là điều kiện dừng lại return BS[0] if not nsau đó? Chỉ trong trường hợp bạn muốn sử dụng các chữ số ưa thích, như tôi làm :)
Arnaud P

@ArnaudP đồng ý. Cái này hoạt động với tôi:return BS[n] if n < b else to_base(n // b) + BN[n % b]
Jens

15

Python không có chức năng tích hợp sẵn để in một số nguyên trong một cơ sở tùy ý. Bạn sẽ phải viết riêng của bạn nếu bạn muốn.


13

Bạn có thể sử dụng baseconv.pytừ dự án của tôi: https://github.com/semente/python-baseconv

Sử dụng mẫu:

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

Có một số bộ chuyển đổi bultin chẳng hạn baseconv.base2, baseconv.base16baseconv.base64.


12

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


Giải pháp tốt đẹp. Trong trường hợp của tôi, tôi đã tránh được sự khó chịu trong clacthời gian tải. Tải trước nhanh hơn gấp ba lần thời gian chạy của đánh giá biểu thức đơn giản trong clac: ví dụ: clac 1+1 đi từ khoảng 40ms đến 140ms.
Đánh dấu

1
Lưu ý rằng numpy.base_repr()có giới hạn 36 là cơ sở của nó. Nếu không, nó sẽ ném mộtValueError
sbdchd

Mà phù hợp với giới hạn của chức năng "int" tích hợp. Các cơ sở lớn hơn yêu cầu quyết định phải làm gì khi hết thư,
cắm vào

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

Đây là một cái khác từ cùng một liên kết

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

base10toN không tính đến trường hợp num == 0.
Craeft

3

Tôi đã thực hiện một gói pip cho việc này.

Tôi khuyên bạn nên sử dụng căn cứ của tôi https://github.com/kamijoutouma/base.py được lấy cảm hứng từ căn cứ.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

tham khảo https://github.com/kamijoutouma/base.py# Unknown-basealphabets để biết những cơ sở nào có thể sử dụng được

EDIT: liên kết pip https://pypi.python.org/pypi/base.py/0.2.2


Điều này hoạt động như một nét duyên dáng cho các căn cứ được chỉ định .
Agi Hammerthief

Đây là câu trả lời tốt nhất! Và cảm ơn cho bao bì pip!
'19

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)

đầu ra:

"1F"


other-basecũng giống như other - basevậy, vì vậy bạn nên sử dụngother_base
mbomb007

Ngoài ra, điều này không hoạt động chính xác nếu decimalbằng không.
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'

1

Một giải pháp đệ quy cho những người quan tâm. Tất nhiên, điều này sẽ không hoạt động với các giá trị nhị phân âm. Bạn sẽ cần phải thực hiện Bổ sung của hai.

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

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

giải trình

Trong bất kỳ cơ sở nào, mọi số đều bằng a1+a2*base**2+a3*base**3..."Nhiệm vụ" là tìm tất cả các.

Đối với mọi N=1,2,3...mã, cô lập mã aN*base**Nbằng cách "moudcing" bởi b để b=base**(N+1) cắt tất cả các phần tử lớn hơn N và cắt tất cả các phần tử mà sê-ri của chúng nhỏ hơn N bằng cách giảm dòng điện mỗi lần gọi bởi func aN*base**N.

Cơ sở% (cơ sở-1) == 1 đối với cơ sở ** p% (cơ sở-1) == 1 và đối với q * cơ sở ^ p% (cơ sở-1) == q chỉ có một ngoại lệ khi q = cơ sở-1 trong đó trả về 0. Để khắc phục rằng trong trường hợp nó trả về 0, func đang kiểm tra có phải là 0 từ cầu xin không.


lợi thế

trong mẫu này chỉ có một phép nhân (thay vì chia) và một số moudulueses tương đối mất một lượng nhỏ thời gian.


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

print(str(round(num, 2)) + "^" + str(power))

vui lòng thêm một số thông tin ngắn gọn rằng những gì bạn đã thực hiện đặc biệt
Farhana

Trong khi điều này có thể trả lời câu hỏi của tác giả, nó thiếu một số từ giải thích và / hoặc liên kết đến tài liệu. Đoạn mã thô không hữu ích lắm nếu không có một số cụm từ xung quanh chúng. Bạn cũng có thể tìm thấy làm thế nào để viết một câu trả lời tốt rất hữu ích. Vui lòng chỉnh sửa câu trả lời của bạn.
hellow

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]   

Trong chức năng này, bạn có thể dễ dàng chuyển đổi bất kỳ số thập phân nào sang cơ sở yêu thích của bạn.
montaqami

Bạn không cần bình luận câu trả lời của riêng bạn, bạn chỉ cần chỉnh sửa nó để thêm giải thích.
Pochmurnik

1

Dưới đây là một ví dụ về cách chuyển đổi một số bất kỳ cơ sở nào sang cơ sở khác.

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

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)

0

Một số ngắn khác (và dễ hiểu hơn imo):

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

Và với xử lý ngoại lệ thích hợp:

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

0

Một giải pháp khác, hoạt động với cơ sở 2 đến 10, cần sửa đổi cho các cơ sở cao hơn:

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

Thí dụ:

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

0

Dưới đây là phiên bản đệ quy xử lý số nguyên đã ký và chữ số tùy chỉnh.

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]

0

Chuỗi không phải là lựa chọn duy nhất để biểu diễn các số: bạn có thể sử dụng danh sách các số nguyên để biểu thị thứ tự của mỗi chữ số. Những người có thể dễ dàng được chuyển đổi thành một chuỗi.

Không có câu trả lời nào từ chối cơ sở <2; và hầu hết sẽ chạy rất chậm hoặc gặp sự cố với tràn ngăn xếp với số lượng rất lớn (chẳng hạn như 56789 ** 43210). Để tránh những thất bại như vậy, hãy giảm nhanh như thế này:

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)

Tốc độ, n_to_basetương đương với strsố lượng lớn (khoảng 0,3 giây trên máy của tôi), nhưng nếu bạn so sánh với hexbạn có thể ngạc nhiên (khoảng 0,3ms trên máy của tôi hoặc nhanh hơn 1000 lần). Lý do là bởi vì số nguyên lớn được lưu trữ trong bộ nhớ trong cơ sở 256 (byte). Mỗi byte đơn giản có thể được chuyển đổi thành một chuỗi hex hai ký tự. Sự liên kết này chỉ xảy ra đối với các cơ sở có quyền hạn của hai, đó là lý do tại sao có các trường hợp đặc biệt cho 2,8 và 16 (và base64, ascii, utf16, utf32).

Hãy xem xét chữ số cuối cùng của một chuỗi thập phân. Làm thế nào nó liên quan đến chuỗi byte tạo thành số nguyên của nó? Hãy dán nhãn các byte s[i]với s[0]là quan trọng nhất (little endian). Sau đó, chữ số cuối cùng là sum([s[i]*(256**i) % 10 for i in range(n)]). Vâng, điều xảy ra là 256 ** i kết thúc bằng 6 cho i> 0 (6 * 6 = 36) sao cho chữ số cuối cùng là (s[0]*5 + sum(s)*6)%10. Từ đó, bạn có thể thấy rằng chữ số cuối cùng phụ thuộc vào tổng của tất cả các byte. Thuộc tính không nhắm mục tiêu này là những gì làm cho việc chuyển đổi sang thập phân khó hơn.


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

Đối với python3, mã của bạn thực hiện điều này: baseConverter (0, 26) -> '' baseConverter (1, 26) -> '0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001' Đối với python2, nó thực hiện điều này: baseConverter ( -> 1 baseConverter (3, 26) -> 3 baseConverter (5, 26) -> 5 baseConverter (26, 26) -> 10 baseConverter (32, 26) -> 16
Drachenfels

0

Vâng, cá nhân tôi sử dụng chức năng này, được viết bởi tôi

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

Đây là cách bạn có thể sử dụng nó

print(to_base(7, base=2))

Đầu ra: "111"

print(to_base(23, base=3))

Đầu ra: "212"

Xin vui lòng đề xuất cải tiến trong mã của tôi.


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

0

Đây là một câu hỏi cũ nhưng tôi nghĩ tôi sẽ chia sẻ câu hỏi của mình vì tôi cảm thấy nó đơn giản hơn những câu trả lời khác (tốt cho các cơ sở từ 2 đến 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

-1

Tôi chưa thấy bất kỳ bộ chuyển đổi nổi nào ở đây. Và tôi đã bỏ lỡ nhóm luôn luôn có ba chữ số.

LÀM:

-numbers trong biểu hiện khoa học (n.nnnnnn*10**(exp)- '10'self.baseDigits[1::-1]/self.to_string(len (self.baseDigits))

-from_ chuỗi-chức năng.

-base 1 -> số La Mã?

-có phức tạp với agles

Vì vậy, đây là giải pháp của tôi:

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)

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

đầu ra:

3ewfdnca0n6ld1ggvfgg

để chuyển đổi sang bất kỳ cơ sở, nghịch đảo cũng dễ dàng.


NameError: global name 'n' is not defined. Được divmod(x, n)cho là divmod(x, b)?
wjandrea
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.