为什么提高精度会使此程序更快?

时间:2019-01-13 13:05:06

标签: python python-3.x performance

我正在解决Euler项目上的问题26,需要计算1 / n重复部分的长度,其中n是1到1000之间的所有整数,并查看哪个数字是最长的重复部分。那意味着我需要我的部门做得更精确。因此,我通过更改getContext().prec来提高自己的十进制精度,但是后来以某种方式提高了精度使程序更快了。我使用Python 3.7运行了该程序。这是代码:

import re
import time
s = time.time()
from decimal import *
getcontext().prec = 500 #This part
recurring = 0
answer = 0
p = re.compile(r"([0-9]+?)\1{3,}")
for i in range(1, 1000):
    f = p.search(str(Decimal(1) / Decimal(i))[5:])
    if f:
        number = f.group(1)
        if len(str(number)) > len(str(recurring)):
            recurring = number
            answer = i

print(answer)
print(time.time() - s)

这是我使用500精度时的结果:

>>> print(answer)
349
>>> print(time.time() - s)
2.923844575881958

...这就是我使用5000精度时得到的结果:

>>> print(answer)
983
>>> print(time.time() - s)
0.07812714576721191

我用500换了5000,不仅给了我正确的答案,因为1 / answer的重复部分可能比500长,而且速度也更快。我已经使用在线Python解释器进行了尝试,它也给了我类似的结果。为什么会这样?

2 个答案:

答案 0 :(得分:2)

它是正则表达式中+和\ 1的组合

方法

我使用了以下测试代码:

import time
import re
import string
t=time.time()
re.compile() # I tried differend regexes here
print(time.time()-t)
def test(n):
    t=time.time()
    match = rex.search(string.ascii_lowercase*n)
    print(match, time.time()-t)

重新启动python会话后,对re.compile的首次调用所花费的时间要长于相同正则表达式的后续编译。

                                        compile(sec)   search (sec)    
REGEX                                   1st     2nd    short   long string
r"(abcdefghijklmnopqrstuvwxyz){6,}"     10^-4   10^-5  10^-5   10^-5
r"(abcdefghijklmnopqrstuvwxyz)\1\1\1\1" 10^-4   10^-5  10^-6   10^-6
r"([a-z]+?)\1\1\1\1"                    10^-4   10^-5  10^-4   10^-5 
r"([a-z]+)\1\1\1\1"                     10^-4   10^-5  10^-4   10^-5
r"([a-z][a-z][a-z][a-z][a-z][a-z][a-z][a-z][a-z][a-z][a-z][a-z][a-z][a-z][a-z][a-z][a-z][a-z][a-z][a-z][a-z][a-z][a-z][a-z][a-z][a-z])\1\1\1\1"
                                        10^-4  10^-5  10^-6  10^-6

有趣的是,对于字符串太短的情况,偶尔r"([a-z]+?)\1\1\1"也会很快(10 ^ -5秒)。

讨论

编译rexex涉及一些缓存,但这不是这里的原因。

似乎组中的+运算符(贪婪和非贪婪)与正则表达式中的\1的组合是错误的。由于某种原因,如果实际匹配,则此组合比不匹配的组合要快。

要了解更多信息,我们可能必须了解sre模块的C源代码

答案 1 :(得分:1)

在prec == 4000附近发生了一些事情。所有答案都等于983,并且时间从4000开始线性变化很小。也许在那里仔细看看。

在2000年附近还有一个小幅度下降。您需要分别测量小数除法和正则表达式搜索所经过的时间,以获取更多信息。

在此图像上:精确(水平)与以秒为单位的时间(垂直) prec vs. time