Sexy primes, «медленный питон» или как я бился о стену непонимания
- воскресенье, 31 мая 2015 г. в 02:11:04
Sexy primes up to: 10k 20k 30k 100k
---------------------------------------------------------
Python2.7 1.49 5.20 11.00 119
Scala2.9.2 0.93 1.41 2.73 20.84
Scala2.9.2 (optimized) 0.32 0.79 1.46 12.01
Sexy primes up to: 10k 20k 30k 100k
---------------------------------------------------------
PyMNg * 0.10 - - 2.46
pypy2 * 0.13 - - 5.44
pypy3 * 0.12 - - 5.69
---------------------------------------------------------
Python3.4 * 1.41 - - 117.69
---------------------------------------------------------
Python2.7 1.49 5.20 11.00 119.00
Scala2.9.2 0.93 1.41 2.73 20.84
Scala2.9.2 (optimized) 0.32 0.79 1.46 12.01
org = 5.69000 s = 5690.00 mils | 2447 sp: [5, 11], [7, 13], ... [99901, 99907], [99923, 99929]
mod1 = 2.45500 s = 2455.00 mils | 2447 sp: [5, 11], [7, 13], ... [99901, 99907], [99923, 99929]
mod2 = 1.24300 s = 1243.00 mils | 2447 sp: [5, 11], [7, 13], ... [99901, 99907], [99923, 99929]
org2 = 3.46800 s = 3468.00 mils | 2447 sp: [5, 11], [7, 13], ... [99901, 99907], [99923, 99929]
max = 0.03200 s = 32.00 mils | 2447 sp: [5, 11], [7, 13], ... [99901, 99907], [99923, 99929]
orgm = 0.13000 s = 130.00 mils | 2447 sp: [5, 11], [7, 13], ... [99901, 99907], [99923, 99929]
siev1 = 0.01200 s = 12.00 mils | 2447 sp: [5, 11], [7, 13], ... [99901, 99907], [99923, 99929]
siev2 = 0.01000 s = 10.00 mils | 2447 sp: [5, 11], [7, 13], ... [99901, 99907], [99923, 99929]
osie1 = 0.01200 s = 12.00 mils | 2447 sp: [5, 11], [7, 13], ... [99901, 99907], [99923, 99929]
osie2 = 0.00200 s = 2.00 mils | 2447 sp: [5, 11], [7, 13], ... [99901, 99907], [99923, 99929]
org = 120.75802 s = 120758.02 mils | 2447 sp: [5, 11], [7, 13], ... [99901, 99907], [99923, 99929]
mod1 = 132.99282 s = 132992.82 mils | 2447 sp: [5, 11], [7, 13], ... [99901, 99907], [99923, 99929]
mod2 = 76.65101 s = 76651.01 mils | 2447 sp: [5, 11], [7, 13], ... [99901, 99907], [99923, 99929]
org2 = 53.42527 s = 53425.27 mils | 2447 sp: [5, 11], [7, 13], ... [99901, 99907], [99923, 99929]
max = 0.44004 s = 440.04 mils | 2447 sp: [5, 11], [7, 13], ... [99901, 99907], [99923, 99929]
orgm = 0.39003 s = 390.03 mils | 2447 sp: [5, 11], [7, 13], ... [99901, 99907], [99923, 99929]
siev1 = 0.04000 s = 40.00 mils | 2447 sp: [5, 11], [7, 13], ... [99901, 99907], [99923, 99929]
siev2 = 0.04250 s = 42.50 mils | 2447 sp: [5, 11], [7, 13], ... [99901, 99907], [99923, 99929]
osie1 = 0.04500 s = 45.00 mils | 2447 sp: [5, 11], [7, 13], ... [99901, 99907], [99923, 99929]
osie2 = 0.04250 s = 42.50 mils | 2447 sp: [5, 11], [7, 13], ... [99901, 99907], [99923, 99929]
max
(остальные просто медленные на таком массиве). max = 5.28500 s = 5285.00 mils | 117207 sp: [5, 11], [7, 13], ... [9999931, 9999937], [9999937, 9999943]
orgm = 12.65600 s = 12656.00 mils | 117207 sp: [5, 11], [7, 13], ... [9999931, 9999937], [9999937, 9999943]
siev1 = 0.51800 s = 518.00 mils | 117207 sp: [5, 11], [7, 13], ... [9999931, 9999937], [9999937, 9999943]
siev2 = 0.23200 s = 232.00 mils | 117207 sp: [5, 11], [7, 13], ... [9999931, 9999937], [9999937, 9999943]
osie1 = 0.26800 s = 268.00 mils | 117207 sp: [5, 11], [7, 13], ... [9999931, 9999937], [9999937, 9999943]
osie2 = 0.22700 s = 227.00 mils | 117207 sp: [5, 11], [7, 13], ... [9999931, 9999937], [9999937, 9999943]
max = 288.81855 s = 288818.55 mils | 117207 sp: [5, 11], [7, 13], ... [9999931, 9999937], [9999937, 9999943]
orgm = 691.96458 s = 691964.58 mils | 117207 sp: [5, 11], [7, 13], ... [9999931, 9999937], [9999937, 9999943]
siev1 = 4.02766 s = 4027.66 mils | 117207 sp: [5, 11], [7, 13], ... [9999931, 9999937], [9999937, 9999943]
siev2 = 4.05016 s = 4050.16 mils | 117207 sp: [5, 11], [7, 13], ... [9999931, 9999937], [9999937, 9999943]
osie1 = 4.69519 s = 4695.19 mils | 117207 sp: [5, 11], [7, 13], ... [9999931, 9999937], [9999937, 9999943]
osie2 = 4.43018 s = 4430.18 mils | 117207 sp: [5, 11], [7, 13], ... [9999931, 9999937], [9999937, 9999943]
siev1
(по той же причине).siev1 = 7.39800 s = 7398.00 mils | 879908 sp: [5, 11], [7, 13], ... [99999617, 99999623], [99999821, 99999827]
siev2 = 2.24500 s = 2245.00 mils | 879908 sp: [5, 11], [7, 13], ... [99999617, 99999623], [99999821, 99999827]
osie1 = 2.53500 s = 2535.00 mils | 879908 sp: [5, 11], [7, 13], ... [99999617, 99999623], [99999821, 99999827]
osie2 = 2.31000 s = 2310.00 mils | 879908 sp: [5, 11], [7, 13], ... [99999617, 99999623], [99999821, 99999827]
siev1 = 41.87118 s = 41871.18 mils | 879908 sp: [5, 11], [7, 13], ... [99999617, 99999623], [99999821, 99999827]
siev2 = 40.71163 s = 40711.63 mils | 879908 sp: [5, 11], [7, 13], ... [99999617, 99999623], [99999821, 99999827]
osie1 = 48.08692 s = 48086.92 mils | 879908 sp: [5, 11], [7, 13], ... [99999617, 99999623], [99999821, 99999827]
osie2 = 44.05426 s = 44054.26 mils | 879908 sp: [5, 11], [7, 13], ... [99999617, 99999623], [99999821, 99999827]
org
. (Только, плз, не надо здесь про «xrange vs range» — я прекрасно представляю, в чем различие, и здесь конкретно оно не суть важно, тем более в 3-м питоне, кроме того, и итерация как-бы «завершенная»).def is_prime(n):
return all((n % i > 0) for i in range(2, n))
# def sexy_primes_below(n):
# return [[j-6, j] for j in range(9, n+1) if is_prime(j) and is_prime(j-6)]
def sexy_primes_below(n):
l = []
for j in range(9, n+1):
if is_prime(j-6) and is_prime(j):
l.append([j-6, j])
return l
primes_below
на мой вариант с прямым циклом не сильно влияет на время исполнения, просто оно наглядней для изменений в последующих вариантах (например сито). Весь цимес в реализации is_prime
, во всяком случае пока.mod1
def is_prime(n):
i = 2
while True:
if not n % i:
return False
i += 1
if i >= n:
return True
return True
mod2
в половину быстрее, если не проверять четные номера (которые, кроме двойки, изначально не prime).def is_prime(n):
if not n % 2:
return False
i = 3
while True:
if n % i == 0:
return False
i += 2
if i >= n:
return True
return True
org2
это то же самое что и mod2
, но в одну строчку используя «сахар».def is_prime(n):
return n % 2 and all(n % i for i in range(3, n, 2))
max
:def is_prime(n):
if not n & 1:
return 0
i = 3
while 1:
if not n % i:
return 0
if i * i > n:
return 1
i += 2
return 1
Намного быстрее, правда.orgm
.def is_prime(n):
#return ((n & 1) and all(n % i for i in range(3, int(math.sqrt(n))+1, 2)))
return ((n & 1) and all(n % i for i in range(3, int(n**0.5)+1, 2)))
sexy_primes_below
, вызвав в нем генерацию сита ну и чтобы не править is_prime
и не вызывать его в цикле, спрашиваем сразу sieve
. siev1
. def primes_sieve(n):
""" temporary "half" mask sieve for primes < n (using bool) """
sieve = [True] * (n//2)
for i in range(3, int(n**0.5)+1, 2):
if sieve[i//2]:
sieve[i*i//2::i] = [False] * ((n-i*i-1)//(2*i)+1)
return sieve
def sexy_primes_below(n):
l = []
sieve = primes_sieve(n+1)
#is_prime = lambda j: (j & 1) and sieve[int(j/2)]
for j in range(9, n+1):
i = j-6
#if (i & 1) and is_prime(i) and is_prime(j):
if (i & 1) and sieve[int(i/2)] and sieve[int(j/2)]:
l.append([i, j])
return l
Этот вариант настолько быстрый, что в PyPy, например, он на 100M выдает практически то же время, что оригинал на 100K. Т.е. проверяя в 2000 раз больше чисел и генерируя на несколько порядков больший список сексуально-простых пар.siev2
, потому что вспомнил о несколько «туповатой» обработке bool в PyPy. Т.е. заменив булевы флажки на 0/1. Этот пример отрабатывает на 100M уже вдвое-трое быстрее оригинала на 100K!osiev1
и osiev2
написал, чтобы в дальнейшем можно было заменить сито для всех чисел, на множество более коротких, т.е. чтобы иметь возможность осуществлять поиск пар инкрементально или блочно. sieve = [1, 1, 1, 0, 1, 1 ...]; # для 3, 5, 7, 9, 11, 13 ...
osieve = [3, 5, 7, 0, 11, 13, ...]; # для 3, 5, 7, 9, 11, 13 ...
osiev1
.def primes_sieve(n):
""" temporary odd direct sieve for primes < n """
sieve = list(range(3, n, 2))
l = len(sieve)
for i in sieve:
if i:
f = (i*i-3) // 2
if f >= l:
break
sieve[f::i] = [0] * -((f-l) // i)
return sieve
def sexy_primes_below(n):
l = []
sieve = primes_sieve(n+1)
#is_prime = lambda j: (j & 1) and sieve[int((j-2)/2)]
for j in range(9, n+1):
i = j-6
#if (i & 1) and is_prime(i) and is_prime(j):
if (i & 1) and sieve[int((i-2)/2)] and sieve[int((j-2)/2)]:
l.append([i, j])
return l
osiev2
просто «чуть» быстрее, т.к. инициирует сито гораздо оптимальнее.def primes_sieve(n):
""" temporary odd direct sieve for primes < n """
#sieve = list(range(3, n, 2))
l = ((n-3)//2)
sieve = [-1] * l
for k in range(3, n, 2):
o = (k-3)//2
i = sieve[o]
if i == -1:
i = sieve[(k-3)//2] = k
if i:
f = (i*i-3) // 2
if f >= l:
break
sieve[f::i] = [0] * -((f-l) // i)
return sieve
sexy-primes-test.py --help
Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.