我正在构建一个生成大量整数的加密程序,它看起来像这样:
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
答案 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)
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