[英]Is it possible to convert a really large int to a string quickly in 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
您在評論中寫道,您希望以十進制格式獲取整數的長度。 您不需要將此整數轉換為字符串,您可以使用“常用對數”代替:
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')
關於“我需要它來實現此功能”的一些快速說明。
[: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(string) % parts
字符。
在你的第二個循環中,你用for i in i
遮蔽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
這應該非常快,因為它完全避免了字符串。 如果您願意,您可以在最后將其更改為字符串,這可能會或可能不會從這里的其他答案中受益,具體取決於您的塊大小。
GMPY2提供了比函數 str 更快的 int 到 str 的轉換
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
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.