Форум сайта python.su
При решении задачки c projecteuler.net. Заморочился с простыми числами.
Реализую эти два способа.
Способ 1
Перебираем все цифры (N), которые оканчиваются на 1, 3, 7 или 9 (всё, что кончается на 0 или 5, явно не простое число ), и делим их на все числа от 3 до корня от N включительно. Цифры 2, 3 и 5, простые числа, заносятся в массив вручную перед началом работы цикла поиска.
Способ 2
Перебираем все цифры (N), которые оканчиваются на 1, 3, 7 или 9 (всё, что кончается на 0 или 5, явно не простое число ), и делим их на все найденные до этого времени простые числа, от 3 до корня от N включительно. Цифры 2, 3 и 5, простые числа, заносятся в массив вручную перед началом работы цикла поиска.
Соответственно реализация:
def primitive1(th):
a = [1,2,3,5]
count = 3
cur = 6
while count < th:
if str(cur)[-1] in '024568':
cur += 1
continue
prim = True
for i in xrange(3,int(math.sqrt(cur))+1):
if not cur%i:
prim = False
break
if prim:
a.append(cur)
count += 1
cur += 1
return a
def primitive2(th):
a = [1,2,3,5]
count = 3
cur = 6
while count < th:
if str(cur)[-1] in '024568':
cur += 1
continue
prim = True
edge = int(math.sqrt(cur))
for i in (x for x in a[2:] if x <= edge):
#print i
if not cur%i:
prim = False
break
if prim:
a.append(cur)
count += 1
cur += 1
return a
p = 200
t1 = Timer("primitive1(%d)" % p,"from __main__ import primitive1")
t2 = Timer("primitive2(%d)" % p,"from __main__ import primitive2")
print "Primitive 1 -", t1.timeit(number=100)
print "Primitive 2 -", t2.timeit(number=100)
Primitive 1 - 0.263126850128
Primitive 2 - 0.511752128601
Отредактировано (Июль 10, 2010 12:02:56)
Офлайн
Потому, что вы используете во втором случае генераторное выражение и срез. Уберите их и будет быстрее.
Офлайн
Убрал срез и поменял генератор на список:
def primitive2(th):
a = [2,3,5]
count = 3
cur = 6
while count < th:
if str(cur)[-1] in '024568':
cur += 1
continue
prim = True
edge = int(sqrt(cur))
for i in [x for x in a if x <= edge]:
#print i
if not cur%i:
prim = False
break
if prim:
a.append(cur)
count += 1
cur += 1
return a
Primitive 1 - 0.223769187927
Primitive 2 - 0.582427024841
for i in (x for x in a if x <= edge):
Primitive 1 - 0.229700803757
Primitive 2 - 0.426733970642
Отредактировано (Июль 11, 2010 01:31:07)
Офлайн
Разобрался вроде.
Торможение давала генерация списка - . Срез дает тоже некоторое торможение, но очень небольшое.
В итоге проблема решилась добавлением условия внутрь цикла, менее красиво, но быстрей.
def primitive2(th):
a = [2,3,5]
count = 3
cur = 6
while count < th:
if str(cur)[-1] in '024568':
cur += 1
continue
prim = True
edge = int(sqrt(cur))
for i in a:
if i > edge: break
if not cur%i:
prim = False
break
if prim:
a.append(cur)
count += 1
cur += 1
return a
Офлайн
>приму любую конструктивную критику и исправления
А вот вам:
Поступаем так:
Primitive 1 - ваша первая версия Primitive 2
Primitive 2 - ваша новая версия Primitive 2
Primitive 3 - вот такая вот функция:
def primitive3(th):
a = [1,2,3,5]
curr = 7
while len(a)<=th:
if all((curr%i != 0 for i in a[1:int(math.sqrt(curr))])):
a.append(curr)
curr += 2
return a
Офлайн
Насчет избавиться от count - согласен, так читабельнее. Сишные привычки изживаются тяжело.
А вот насчет остального, по тому же списку
Primitive 1 - первая версия Primitive 2
Primitive 2 - новая версия Primitive 2
Primitive 3 - функция Evgeny:
Primitive 1 - 0.176831960678
Primitive 2 - 0.0816051959991
Primitive 3 - 0.126677036285
Офлайн
И еще момент -
curr += 2
if str(cur)[-1] in '024568':
for i in a[1:int(math.sqrt(curr))]
for i in a:
if i > math.sqrt(curr): break
Отредактировано (Июль 11, 2010 09:03:53)
Офлайн
DuoVПожалуйста.
Разобрался вроде.
Торможение давала генерация списка - .
Спасибо, за совет.
def primitive4(th):
a = [3,5]
count = 3
cur = 7
while count < th:
if cur % 10 in (1,3,7,9):
prim = True
edge = sqrt(cur)
for i in a:
if i > edge:
break
if not cur % i:
prim = False
break
if prim:
a.append(cur)
count += 1
cur += 1
return [1,2] + a
Отредактировано (Июль 11, 2010 10:51:28)
Офлайн
EdСпасибо, это гораздо чем проверять последнюю цифру через строку. Но cur += 2 все таки оказывается быстрее - все таки отбрасываем деление и проверку вхождения, что компенсирует “лишнюю” проверку чисел оканчивающихся на 5.
Пожалуйста.
Вот вам еще один вариант на основе вашего - еще быстрее и ужаснее :)PS: Наш код генерит на одно число больше(201), чем просят. Так надо?while count < th:
if cur % 10 in (1,3,7,9):
prim = True
Отредактировано (Июль 11, 2010 11:05:26)
Офлайн
Я, видимо, что-то пропустил. Покажите, пожалуйста, вариант с count += 2 быстрее моего.
Кстати, если хотите поупражняться в производительности производства prime numbers(и не только), то вам сюда: http://www.spoj.pl/problems/PRIME1/
Можно совместно.
Офлайн