простое сито, возвращающее некоторые странные числа

Я пытаюсь разработать решето простых чисел, и на бумаге мой алгоритм имеет смысл на бумаге, но возвращает очень короткий выбор составных чисел среди простых чисел, ТОЛЬКО выше квадратного корня.

Например, с пределом (нахождение всех простых чисел до предела) 10000 (что имеет квадратный корень из 100), составные числа, которые он смешал с его простыми числами, составляют 115, 119, 121 и 125 (все очень близко к (и выше!) 100).

Пожалуйста, дайте мне знать, что не так с моим кодом и какие части нужно исправить / как это исправить.

УТОЧНЕНИЕ: меня беспокоит составной (не простые числа), который он возвращает, где в моем тестировании на простоту я ошибся и как я могу это исправить?

Вот мое сито:

def primes(limit):
    # Just make an empty list where the primes go
    prime = []
    # This next for loop just adds all the numbers of the form 6n+/-1 to the list, as all primes are of this form
    for i in range(1,limit / 6 + 1):
        prime.append(6*i - 1)
        prime.append(6*i + 1)
    # If the limit is divisible by 6, the last number on the list is sometimes over the limit
    if limit % 6 == 0 and prime[-1] > limit:
        prime.remove(prime[-1])
    # This next line just finds the place of the 'square root' of the limit, which is as high as it has to check for factors
    squareroot = min(range(len(prime)), key=lambda i: abs(prime[i]-(limit**0.5))) + 1
    # Removing composites BELOW the square root
    for p in prime[:squareroot][:]:
        for f in range(2, int(p ** 0.5) + 1):
            if p % f == 0:
                prime.remove(p)
                break
    # Removing composites ABOVE the square root
    for f in prime[:squareroot][:]:
        for p in prime[squareroot:]:
            if p % f == 0:
                prime.remove(p)
    return [2, 3] + prime

person Robbie Barrat    schedule 17.03.2016    source источник
comment
отступы шаткие только в первой строке. Быстрее выбрать все строки под этой первой строкой и нажать кнопку кода {}, чем ввести это предложение.   -  person    schedule 17.03.2016
comment
Я не понимаю вашей реальной проблемы: вы беспокоитесь, что получаете значения выше 100, или беспокоитесь, что получаете составные числа?   -  person    schedule 17.03.2016
comment
Не все простые числа имеют форму 6n +/- 1.   -  person Peter Wood    schedule 17.03.2016
comment
Питер Вуд - да, по крайней мере, простые числа больше 2 и 3. Это математически доказано. Что касается Эверта, я беспокоюсь, что получаю составные числа (например, 115, 119 и т. Д.), Но все получаемые мной составные числа находятся прямо над квадратным корнем из предела (в данном случае 10 000). Мне интересно, почему я получаю эти композиты и как я могу перестать их получать.   -  person Robbie Barrat    schedule 17.03.2016
comment
Но ваш список простых чисел не включает 2 и 3.   -  person Peter Wood    schedule 17.03.2016
comment
С каким наименьшим limit это не удается?   -  person Peter Wood    schedule 17.03.2016
comment
Питер - список, который возвращает моя функция, на самом деле включает 2 и 3 (посмотрите на последнюю строку), наименьшее ограничение, с которым она не справляется, составляет 901, поскольку она возвращает 35 как простое число. Я хотел бы обратить внимание на тот факт, что единственные ошибки, которые он делает, находятся очень близко к квадратному корню из предела.   -  person Robbie Barrat    schedule 17.03.2016
comment
Я понимаю. Вам не нужно рассматривать 2 и 3 как факторы, потому что кратные 6 имеют 2 и 3 как множители, а +/-1 - нет.   -  person Peter Wood    schedule 17.03.2016
comment
limit=1000 не имеет 115 в простых числах, но limit=10000 имеет. limit=8101 это когда появляется ..   -  person Peter Wood    schedule 17.03.2016


Ответы (3)


Одна из причин, по которой вы получаете композиты выше квадратного корня, заключается в том, как построены ваши циклы. Когда элемент удаляется из списка, все элементы с более высокими индексами сдвигаются вниз на один. Итак, когда элемент удаляется в первом цикле, квадратный корень перемещается вниз. Когда начинается второй цикл, squareroot больше не является индексом квадратного корня.

# Removing composites BELOW the square root
for p in prime[:squareroot][:]:
    for f in range(2, int(p ** 0.5) + 1):
        if p % f == 0:
            prime.remove(p)  # <- you removed an item from `prime`, so the
            break            # square root is now at prime[squareroot - 1]

# Removing composites ABOVE the square root
for f in prime[:squareroot][:]:    #    now p[squareroot] is actually a number
    for p in prime[squareroot:]:   # <- above the real square root, so this 
        if p % f == 0:             #    loop starts too high
            prime.remove(p)

Один из способов исправить это - изменить значение squareroot всякий раз, когда значение удаляется в первом цикле. Другой вариант - пересчитать squareroot перед вторым циклом.

Как правило, добавлять или удалять элементы из списка во время итерации по списку - плохая идея. Например, элементы можно пометить (например, установить для них ноль или Нет) за один проход, а затем немаркированные элементы можно скопировать за второй проход.

В Edit добавлен пример кода для отметки композитов:

# Removing composites BELOW the square root
for i,p in enumerate(prime[:squareroot]):
    for f in range(2, int(p ** 0.5) + 1):
        if p % f == 0:
            prime[i] = 0  # <- mark composites
            break         

# Removing composites ABOVE the square root
for f in prime[:squareroot]:    
    if f == 0: 
        continue                              # skip composites
    for i,p in enumerate(prime[squareroot:]): # <- this loop is okay now
        if p % f == 0:            
            prime[i] = 0                      # mark composite

# at this point, prime contains 0's where the compsites were found
# and non-zeros for the primes.  Just need to collect all the
# non-zero elements.
result = []         
for p in prime:     
    if p:                    
        result.append(p)

Есть и другие проблемы с вашим кодом, но это должно дать ответ на ваш непосредственный вопрос. По мере того, как вы станете более опытным с python, вы увидите дальнейшие улучшения, которые вы можете сделать (простое решето можно записать примерно на 6 строках python).

person RootTwo    schedule 17.03.2016
comment
Спасибо - я слышал, что удаление элементов во время итерации может вызвать проблемы, но есть ли способ избежать этого? - person Robbie Barrat; 17.03.2016
comment
добавлен пример кода, который не удаляет элементы из prime во время итерации по нему. - person RootTwo; 17.03.2016

После удаления простых чисел, меньших квадратного корня, вы больше не сможете использовать squareroot в качестве индекса в primes, поскольку длина primes изменится.

person T. Silver    schedule 17.03.2016

Я исправил это на основе ответа Т. Сильвера - я просто сделал так, что после того, как убедился, что все, что ниже квадратного корня из предела, является простым, он снова нашел квадратный корень. Вот фиксированный код:

# Just make an empty list where the primes go
prime = []
# This next for loop just adds all the numbers of the form 6n+/-1 to the list, as all primes are of this form
for i in range(1,limit / 6 + 1):
    prime.append(6*i - 1)
    prime.append(6*i + 1)
# If the limit is divisible by 6, the last number on the list is sometimes over the limit
if limit % 6 == 0 and prime[-1] > limit:
    prime.remove(prime[-1])
# This next line just finds the place of the 'square root' of the limit, which is as high as it has to check for factors
squareroot = min(range(len(prime)), key=lambda i: abs(prime[i]-(limit**0.5))) + 1
# Removing composites BELOW the square root
for p in prime[:squareroot][:]:
    for f in range(2, int(p ** 0.5) + 1):
        if p % f == 0:
            prime.remove(p)
            break
# Here's where i put the fix!
squareroot = min(range(len(prime)), key=lambda i: abs(prime[i]-(limit**0.5))) + 1
# Removing composites ABOVE the square root
for f in prime[:squareroot][:]:
    for p in prime[squareroot:]:
        if p % f == 0:
            prime.remove(p)
return [2, 3] + prime
person Robbie Barrat    schedule 17.03.2016