是否可以在python中将很大的int快速转换为字符串

时间:2019-11-23 15:36:00

标签: python

我正在构建一个生成大量整数的加密程序,它看起来像这样:

a = plaintextOrd**bigNumber

当我这样做

a = str(a)

需要28分钟以上。

有没有办法像使用内置的str()函数那样更快地转换整数?

我需要将其作为字符串的原因是由于此功能:

def divideStringIntoParts(parts,string):
    parts = int(parts)
    a = len(string)//parts

    new = []
    firstTime = True
    secondTime = True
    for i in range(parts):
        if firstTime:
            new.append(string[:a])
            firstTime = False
        elif secondTime:
            new.append(string[a:a+a])
            secondTime = False
        else:
            new.append(string[a*i:a*(i+1)])

    string2 = ""
    for i in new:
        for i in i:
            string2 += i

    if len(string2) - len(string) != 0:
        lettersNeeded = len(string) - len(string2)
        for i in range(lettersNeeded):
            new[-1] += string[len(string2) + i] 

    return new

3 个答案:

答案 0 :(得分:3)

您在注释中写道,您希望以十进制格式获取整数的长度。您无需将此整数转换为字符串,可以改用"common logarithm"

import math
math.ceil(math.log(a, 10))

此外,如果您知道:

a = plaintextOrd**bigNumber

然后math.log(a, 10)等于math.log(plaintextOrd, 10) * bigNumber,它的计算时间不会超过几毫秒:

>>> plaintextOrd = 12345
>>> bigNumber = 67890
>>> a = plaintextOrd**bigNumber
>>> len(str(a))
277772
>>> import math
>>> math.ceil(math.log(a, 10))
277772
>>> math.ceil(math.log(plaintextOrd, 10) * bigNumber)
277772

即使a不适合您的硬盘驱动器,它也可以正常工作:

>>> math.ceil(math.log(123456789, 10) * 123456789012345678901234567890)
998952457326621672529828249600

如@ kaya3所述,Python标准浮点数不够精确,无法描述这么多数字的确切长度。

您可以使用mpmath(任意精度浮点算法)来获得所需精度的结果:

>>> from mpmath import mp
>>> mp.dps = 1000
>>> mp.ceil(mp.log(123456789, 10) * mp.mpf('123456789012345678901234567890'))
mpf('998952457326621684655868656199.0')

答案 1 :(得分:2)

有关“我需要此功能”的一些简短说明。

  • 您不需要第一/第二逻辑:
    • [:a] == [a*0:a*(0+1)]
    • [a:a+a] == [a*1:a*(1+1)]

所以我们有

    new = []
    for i in range(parts):
        new.append(string[a*i:a*(i+1)])

或仅new = [string[a*i:a*(i+1)] for i in range(parts)]

请注意,您已静默丢弃了最后len(strong) % parts个字符。

在第二个循环中,您用i遮盖了for i in i,这虽然可行,但很尴尬且危险。也可以将其替换为string2 = ''.join(new),这意味着您可以执行string2 = string[:-(len(string) % parts)]

然后,您将查看字符串的长度是否相同,然后将多余的字母添加到最后一个列表的末尾。这有点令人惊讶,例如你会

>>> divideStringIntoParts(3, '0123456789a')
['012', '345', '6789a']

当大多数算法会产生有利于均匀分布的内容以及较早的元素时,例如:

>>> divideStringIntoParts(3, '0123456789a')
['0124', '4567', '89a']

无论如何,我们看到您在这里根本不关心字符串的值,而只是在乎它的位数。因此,您可以按以下方式重写函数。

def divide_number_into_parts(number, parts):
    '''
    >>> divide_number_into_parts(12345678901, 3)
    [123, 456, 78901]
    '''
    total_digits = math.ceil(math.log(number + 1, 10))
    part_digits = total_digits // parts
    extra_digits = total_digits % parts

    remaining = number
    results = []
    for i in range(parts):
        to_take = part_digits
        if i == 0:
            to_take += extra_digits
        digits, remaining = take_digits(remaining, to_take)
        results.append(digits)
    # Reverse results, since we go from the end to the beginning
    return results[::-1]


def take_digits(number, digits):
    '''
    Removes the last <digits> digits from number.
    Returns those digits along with the remainder, e.g.:
    >>> take_digits(12345, 2)
    (45, 123)
    '''
    mod = 10 ** digits
    return number % mod, number // mod

这应该非常快,因为它完全避免了字符串。您可以根据需要将其更改为字符串结尾,具体取决于块大小,这可能会或可能不会从此处的其他答案中受益。

答案 2 :(得分:1)

GMPY2

提供了从int到str的比函数str更快的转换。

Source of Example Below

import time
from gmpy2 import mpz

# Test number (Large)
x = 123456789**12345

# int to str using Python str()
start = time.time()
python_str = str(x)
end = time.time()

print('str conversion time {0:.4f} seconds'.format(end - start))

# int to str using GMPY2 module
start = time.time()
r = mpz(x)
gmpy2_str = r.digits()
end = time.time()

print('GMPY2 conversion time {0:.4f} seconds'.format(end - start))
print('Length of 123456789**12345 is: {:,}'.format(len(python_str)))
print('str result == GMPY2 result {}'.format(python_str==gmpy2_str))

结果(GMPY2测试速度提高了12倍)

str conversion time 0.3820 seconds
GMPY2 conversion time 0.0310 seconds
Length of 123456789**12345 is: 99,890
str result == GMPY2 result True