我有两个我在python中编写过的sieves,如果可能的话,我想帮助优化它们。 divisorSieve计算所有数字的除数,最大为n
。列表的每个索引都包含其除数列表。 numDivisorSieve只计算每个索引具有的除数的数量,但不存储除数本身。这些筛子的工作方式与您使用Eratosthenes筛子的方式类似,可以计算最多n
的所有素数。
def divisorSieve(n):
divs = [[1] for x in xrange(0, n + 1)]
divs[0] = [0]
for i in xrange(2, n + 1):
for j in xrange(1, n / i + 1):
divs[i * j] += [i]
return divs
def numDivisorSieve(n):
divs = [1] * (n + 1)
divs[0] = 0
for i in xrange(2, n + 1):
for j in xrange(1, n / i + 1):
divs[i * j] += 1
return divs
#Timer test for function
if __name__=='__main__':
from timeit import Timer
n = ...
t1 = Timer(lambda: divisorSieve(n))
print n, t1.timeit(number=1)
结果:
-----n-----|--time(divSieve)--|--time(numDivSieve)--
100,000 | 0.452978167569 | 0.187762331281
200,000 | 0.98932170181 | 0.362314797537
300,000 | 1.6338203645 | 0.55124339118
400,000 | 2.17913634385 | 0.748340797412
500,000 | 2.84024755862 | 0.959312993718
600,000 | 3.46395907197 | 1.17777010636
700,000 | 4.11840766312 | 1.38268800149
800,000 | 4.77613733906 | 1.62560614543
900,000 | 5.4634148162 | 1.83002270324
1,000,000 | 6.11017136282 | 2.10247496423
2,000,000 | 13.0507389438 | 4.59150618897
3,000,000 | 20.6068050631 | 7.24799900479
4,000,000 | 28.3432841948 | 10.1484527586
5,000,000 | 36.4113970268 | 12.7670585308
6,000,000 | 44.4017867139 | 15.4226118057
7,000,000 | 52.4697580394 | 18.2902677738
8,000,000 | 61.4056966474 | 21.1247001928
9,000,000 | 69.7948510294 | 23.8988925173
10,000,000 | 78.639434285 | 26.8588813211
20,000,000 | N/A | 56.2527237669 (waited for a while but divisorSieve didn't finish)
30,000,000 | MemoryError | 86.8917332214
40,000,000 | MemoryError | 118.457179822
50,000,000 | MemoryError | 149.526622815
60,000,000 | MemoryError | 181.627320396
70,000,000 | MemoryError | 214.17467749
80,000,000 | MemoryError | 246.23677614
90,000,000 | MemoryError | 279.53308422
100,000,000 | MemoryError | 314.813166014
结果非常好,我很高兴我能够做到这一点,但我希望得到它更快。如果可能的话,我希望使用divisorSieve以合理的速度获得 100,000,000 。虽然这也会导致问题, 30,000,000 + 的任何内容在divisorSieve中抛出MemoryError
divs = [[1] for x in xrange(0, n + 1)]
。 numDivisorSieve允许运行完整的 100,000,000 。
我尝试用divs = [1] * (n + 1)
和divs = array.array('i', [1] * (n + 1))
替换numDivisorSieve的divs = numpy.ones((n + 1), dtype='int')
,但两者都导致速度损失(数组略有差异,numpy差异大得多)。我希望由于numDivisorSieve的效率会有所下降,所以divisorSieve也是如此。当然,我总是有机会错误地使用其中一个或两个,因为我不习惯其中任何一个。
我很感激你能给我的任何帮助。我希望我提供了足够的细节。谢谢。
答案 0 :(得分:1)
替换
divs[i * j] += [i]
与
divs[i * j].append(i)
答案 1 :(得分:0)
你可以替换:
divs = [[1] for x in xrange(0, n + 1)]
与
divs = [[1]] * (n + 1)
我发现第二个选项明显更快(在mem上不确定,请参阅下面的输出)
In [24]: t1=timeit.Timer(stmt='[[1]] * 1000')
In [25]: t2=timeit.Timer(stmt='[[1] for i in xrange(1000)]')
In [26]: t1.timeit(number=10000)
Out[26]: 0.06668901443481445
In [27]: t2.timeit(number=10000)
Out[27]: 1.5391979217529297