Как создать наиболее компактное отображение n → isprime (n) с точностью до N?

Естественно, для bool isprime(number) была бы структура данных, которую я мог бы запросить.
Я определяю лучший алгоритм, чтобы быть алгоритмом, который создает структуру данных с наименьшим потреблением памяти для диапазона (1, N ], где N - константа.
Просто пример того, что я ищу: я мог бы представить каждое нечетное число одним битом, например, для данного диапазона чисел (1, 10], начинается с 3: 1110

Следующий словарь можно сжать больше, не так ли? Я мог бы исключить число, кратное пяти, с помощью некоторой работы, но числа, оканчивающиеся на 1, 3, 7 или 9, должны присутствовать в массиве битов.

Как решить проблему?


person AraK    schedule 26.11.2009    source источник
comment
Ваш запрос немного расплывчатый. Вы даете подпись, которая проверяет одно число, но затем запрашиваете структуру данных (1, N). Вам нужен алгоритм, который генерирует словарь ‹int, bool› или просто одноразовую функцию, которая проверяет, является ли одно число премьер?   -  person Michael Haren    schedule 26.11.2009
comment
@Michael Простите, это лучшее описание, которое я мог придумать. Я ищу именно то, что вы говорите: логический словарь. Хотелось бы минимизировать пространство словаря. Спасибо :)   -  person AraK    schedule 26.11.2009
comment
Если это то, что вы ищете, вас уже спрашивают: stackoverflow.com/questions/1032427/   -  person Ben S    schedule 26.11.2009
comment
Вам нужно будет спросить у АНБ   -  person Charles Bretana    schedule 26.11.2009
comment
связанные: тест простоты Миллера – Рабина в Python   -  person jfs    schedule 26.04.2016


Ответы (31)


Есть много способов выполнить тест на простоту.

На самом деле нет структуры данных, которую вы могли бы запросить. Если вам нужно проверить много чисел, вам, вероятно, следует запустить вероятностный тест, поскольку они быстрее, а затем выполните детерминированный тест, чтобы убедиться, что число простое.

Вы должны знать, что математика, лежащая в основе самых быстрых алгоритмов, не для слабонервных.

person Ben S    schedule 26.11.2009
comment
Миллер-Рабин - популярный быстрый вероятностный тест, с которого можно начать. - person qwr; 07.08.2016

Самый быстрый алгоритм для общего первичного тестирования - AKS. Статья в Википедии подробно описывает это и ссылается на исходную статью.

Если вы хотите найти большие числа, изучите простые числа, которые имеют особую форму, например простые числа Мерсенна.

Алгоритм, который я обычно реализую (простой для понимания и кодирования), выглядит следующим образом (на Python):

def isprime(n):
    """Returns True if n is prime."""
    if n == 2:
        return True
    if n == 3:
        return True
    if n % 2 == 0:
        return False
    if n % 3 == 0:
        return False

    i = 5
    w = 2

    while i * i <= n:
        if n % i == 0:
            return False

        i += w
        w = 6 - w

    return True

Это вариант классического алгоритма O(sqrt(N)). Он использует тот факт, что простое число (кроме 2 и 3) имеет форму 6k - 1 или 6k + 1, и рассматривает только делители этой формы.

Иногда, если мне действительно нужна скорость и ограничен диапазон, я реализую тест псевдопростого числа на основе Маленькая теорема Ферма. Если мне действительно нужна более высокая скорость (т.е. вообще избегать алгоритма O (sqrt (N))), я предварительно вычисляю ложные срабатывания (см. Кармайкл чисел) и выполните бинарный поиск. Это, безусловно, самый быстрый тест, который я когда-либо проводил, единственный недостаток - ограниченный диапазон.

person Alexandru    schedule 26.11.2009
comment
Строго говоря, Carmicheals недостаточно. Ваш псевдопростой тест также не должен случайно пропустить правильную базу, необходимую для опровержения FLT. Алгоритм сильного псевдопростого числа превосходит то, что в нем нет Carmicheals, но вы все равно не можете быть уверены в этом, если не проверите хотя бы одну четверть диапазона. Если вы не ограничены диапазоном, то мне кажется, что использование SPP + чего-то вроде pollard rho для классификации подавляющего большинства чисел первого прохода перед использованием чего-то более тяжелого - правильный подход. - person Paul Hsieh; 26.11.2009
comment
@Paul Hsieh: изменил формулировку, теперь это лучше? - person Alexandru; 26.11.2009
comment
Два вопроса: не могли бы вы лучше объяснить, что такое переменные i и w, и что подразумевается под формой 6k-1 и 6k+1? Спасибо за понимание и образец кода (который я пытаюсь понять) - person Freedom_Ben; 08.08.2014
comment
@Freedom_Ben Вот, quora.com/ - person Alan Dong; 18.01.2015
comment
Разве не лучше было бы вычислить sqrt из n один раз и сравнить i с ним, а не вычислять i * i каждый цикл цикла? - person pedros; 18.05.2015
comment
На самом деле AKS - НЕ самая быстрая реализация. - person Dschoni; 14.09.2015
comment
@Dschoni ... но вы не можете разместить здесь самую быструю реализацию в полях комментариев, чтобы поделиться с нами? - person GreenAsJade; 14.02.2016
comment
@GreenAsJade: Вопрос в том виде, в каком он задан, неоднозначен, когда дело касается проверок на простоту. В принятом ответе говорится, что вам нужно выбирать между вероятностным и детерминированным подходом, первый из которых намного быстрее. - person Dschoni; 15.02.2016
comment
Когда дело доходит до детерминированных тестов, ECPP (скорее всего, в реализации Goldwasser) должен быть быстрее, чем AKS. - person Dschoni; 15.02.2016
comment
Очень быстрое решение! Спасибо! - person PanGalactic; 09.04.2016
comment
Проверьте это с помощью n = int(subprocess.check_output('openssl prime -generate -bits 2048 -hex'.split()), 16): P - person Nick T; 20.04.2016
comment
Я здесь не эксперт, но я верю, что если вы проверите делимость на основание перед тем, как запускать тест на простую вероятность Ферма, вы обойдете проблему, которую доставляет вам Кармайклс. Бывший. 561 - это Кармайкл, но если вы разделите на 3 перед тестированием теста Ферма по основанию 3, вы обнаружите, что он идеально делится и явно составлен. Я даже не понимаю, почему люди спотыкаются с Кармайклзом на этих тестах. Мой первый шаг - проверка делимости по каждому основанию, которое я использую. Вы все равно должны это сделать, так как база должна быть взаимно простой. - person CogitoErgoCogitoSum; 23.07.2017
comment
Является ли это приблизительным, или я могу положиться на это для создания списков простых чисел в заданном диапазоне? Это определенно намного быстрее, чем все, что я пробовал сейчас. Мой первоначальный (читай: тупой) метод занял 1:17, чтобы проверить, что 100000007 является простым, мой второй метод занял половину этого, 37 секунд, а это ... заняло около 0,3 секунды! : O - person Daniel Springer; 19.07.2018
comment
Не справляется с номером 1 :( - person Damjan Pavlica; 22.08.2018
comment
@DamjanPavlica Добавление if n < 2: return False вверху исправляет это. - person Unmitigated; 10.06.2021

На мой взгляд, лучший метод - это использовать то, что было раньше.

В Интернете есть списки первых N простых чисел с N простирающимися по крайней мере до пятидесяти миллионов . Загрузите файлы и используйте их, это, вероятно, будет намного быстрее, чем любой другой метод, который вы придумаете.

Если вам нужен реальный алгоритм для создания ваших собственных простых чисел, в Википедии есть много хороших материалов о простых числах здесь, включая ссылки на различные методы для этого и первичное тестирование здесь, обе вероятности -основные и быстродетерминированные методы.

Необходимо приложить согласованные усилия, чтобы найти первый миллиард (или даже больше) простых чисел и опубликовать их где-нибудь в сети, чтобы люди могли перестать делать одну и ту же работу снова и снова и ... :-)

person paxdiablo    schedule 26.11.2009
comment
@hamedbh: Интересно. Вы пробовали скачать эти файлы? Похоже, их не существует. - person paxdiablo; 07.12.2016
comment
Боюсь, что пока нет: я просто быстро искал во время обеденного перерыва. Я удалю эту ссылку на случай, если в ней есть что-нибудь злонамеренное. Извините, мне действительно нужно было сначала это проверить. - person Hamed; 07.12.2016
comment
это звучит очень интересно .... было бы хорошо, если бы мы сохранили их в массиве long long int ... - person Aadhil RF; 28.04.2017
comment
Такие списки действительно существуют. Я видел их много лет назад, но никогда не думал их загружать. По правде говоря, они занимают много места (условно говоря), и их не следует включать в программы, которые продаются или распространяются. Более того, они всегда и навсегда останутся неполными. В некотором роде имеет смысл проверять каждое число, которое встречается на практике во время использования программ, поскольку таким образом будет проверено гораздо меньше, чем длина любого списка, который у вас может быть. Кроме того, я думаю, что pax не понимает, что цель основных алгоритмов в большинстве случаев состоит в том, чтобы проверить эффективность / скорость, а не на самом деле найти простые числа. - person CogitoErgoCogitoSum; 23.07.2017
comment
@CogitoErgoCogitoSum, согласитесь, что список всех простых чисел навсегда устареет, поскольку я видел математическое доказательство того, что их число бесконечно. Однако вряд ли список первых x простых чисел будет неполным после того, как он будет построен :-) - person paxdiablo; 25.07.2017
comment
Верно, но есть методы хранения лучше, чем линейное чтение из файла. Если вы действительно хотите читать из сохраненного набора предварительно сгенерированных простых чисел, попробуйте более сложную структуру данных, которая ускоряет проблему. - person CogitoErgoCogitoSum; 25.07.2017

Можно использовать sympy.

import sympy

sympy.ntheory.primetest.isprime(33393939393929292929292911111111)

True

Из sympy docs. Первый шаг - поиск тривиальных факторов, которые, если они найдены, позволяют быстро вернуть их. Затем, если сито достаточно велико, воспользуйтесь поиском на сите пополам. Для малых чисел выполняется набор детерминированных тестов Миллера-Рабина с основаниями, которые, как известно, не имеют контрпримеров в своем диапазоне. Наконец, если число больше 2 ^ 64, выполняется строгий тест BPSW. Хотя это вероятный простой тест и мы считаем, что контрпримеры существуют, известных контрпримеров нет

person LetzerWille    schedule 26.08.2018
comment
Алгоритм - это последовательность четко определенных шагов, которая определяет абстрактное решение проблемы. - какова возможная последовательность шагов в представленном коде? Что это memory consumption? - person greybeard; 26.08.2018
comment
@greybeard. Из sympy docs. Первый шаг - поиск тривиальных факторов, которые, если они найдены, позволяют быстро вернуть их. Затем, если сито достаточно велико, воспользуйтесь поиском на сите пополам. Для малых чисел выполняется набор детерминированных тестов Миллера-Рабина с основаниями, которые, как известно, не имеют контрпримеров в своем диапазоне. Наконец, если число больше 2 ^ 64, выполняется строгий тест BPSW. Хотя это вероятный простой тест и мы считаем, что контрпримеры существуют, известных контрпримеров нет. - person LetzerWille; 26.08.2018

bool isPrime(int n)
{
    // Corner cases
    if (n <= 1)  return false;
    if (n <= 3)  return true;
 
    // This is checked so that we can skip 
    // middle five numbers in below loop
    if (n%2 == 0 || n%3 == 0) return false;
 
    for (int i=5; i*i<=n; i=i+6)
        if (n%i == 0 || n%(i+2) == 0)
           return false;
 
    return true;
}

Это просто реализация c ++ вышеупомянутого алгоритма AKS

person saurabh kumar    schedule 17.05.2017
comment
Это один из самых эффективных детерминированных алгоритмов, с которыми я сталкивался, да, но это не реализация AKS. Система AKS намного новее описанного алгоритма. Это, возможно, более эффективно, но несколько сложно реализовать, я думаю, из-за потенциально астрономически больших факториалов / биномиальных коэффициентов. - person CogitoErgoCogitoSum; 23.07.2017
comment
Чем это отличается от (не) ответа Дерри Лихи (кроме C вместо Java)? Как этот ответ What is the algorithm that produces a data structure with lowest memory consumption for the range (1, N]? - person greybeard; 03.02.2018
comment
Как (n% i == 0 || n% (i + 2) == 0) соответствует 6n + 1 и 6n-1? - person yesh; 08.03.2018
comment
@YeshwanthVenkatesh: How does (n%i == 0 || n%(i+2) == 0) correspond to 6n+1 & 6n-1? часть ответа - разные роли для n, другая - 6n + 1 & 6n-1 эквивалентна (6n-1) +0 & (6n -1) + 2 *. - person greybeard; 14.03.2018
comment
Также обратите внимание, что этот алгоритм не дает правильного результата для 5 и 7. - person Athan Clark; 14.02.2020
comment
Вам также может быть лучше проверить, равно ли число 6n +/- 1 перед циклом. В противном случае он гарантированно будет непростым, что сделает цикл ненужным. - person paxdiablo; 13.05.2021

Согласно Википедии, Сито Эратосфена имеет сложность O(n * (log n) * (log log n)) и требует O(n) памяти - так что это довольно хорошее место для начала, если вы не тестируете особенно большие числа.

person matt b    schedule 26.11.2009
comment
Извините, я знаю, что мое описание расплывчато, я не смотрю на SOE :) посмотрите мой комментарий @Michael - person AraK; 26.11.2009
comment
@AraK: Вы говорите, что хотите, чтобы структура данных сохраняла статус примитивности всех n до определенного предела. Хотя специализированные функции проверки простоты будут быстрее для любого заданного n, если вы хотите знать все результаты от 2 до n с минимальными затратами, сито Эратосфена с оптимизированным хранилищем (например, с использованием байта для представления состояния простоты все числа в блоке из 30 после удаления всех чисел, делящихся на 2, 3 и 5, и жестко запрограммированных простых чисел меньше 30) - вот как вы его заполните. Практически только для заполнения до предела (например, с 4 ГБ ОЗУ вы можете сохранить до ~ 129 миллиардов). - person ShadowRanger; 14.10.2020

Я сравнил эффективность самых популярных предложений, чтобы определить, является ли число простым. Я использовал python 3.6 на ubuntu 17.10; Я тестировал числа до 100000 (вы можете протестировать с большими числами, используя мой код ниже).

Этот первый график сравнивает функции (которые объясняются ниже в моем ответе), показывая, что последние функции не растут так быстро, как первая, при увеличении чисел.

plot1

А на втором графике мы видим, что в случае простых чисел время неуклонно растет, но непростые числа не растут во времени так быстро (потому что большинство из них можно исключить на раннем этапе).

plot2

Вот функции, которые я использовал:

  1. этот ответ и этот ответ предложил конструкцию с использованием all():

    def is_prime_1(n):
        return n > 1 and all(n % i for i in range(2, int(math.sqrt(n)) + 1))
    
  2. В этом ответе использовался какой-то цикл while:

    def is_prime_2(n):
        if n <= 1:
            return False
        if n == 2:
            return True
        if n == 3:
            return True
        if n % 2 == 0:
            return False
        if n % 3 == 0:
            return False
    
        i = 5
        w = 2
        while i * i <= n:
            if n % i == 0:
                return False
            i += w
            w = 6 - w
    
        return True
    
  3. Этот ответ включает версию с for циклом:

    def is_prime_3(n):
        if n <= 1:
            return False
    
        if n % 2 == 0 and n > 2:
            return False
    
        for i in range(3, int(math.sqrt(n)) + 1, 2):
            if n % i == 0:
                return False
    
        return True
    
  4. И я смешал несколько идей из других ответов в новый:

    def is_prime_4(n):
        if n <= 1:          # negative numbers, 0 or 1
            return False
        if n <= 3:          # 2 and 3
            return True
        if n % 2 == 0 or n % 3 == 0:
            return False
    
        for i in range(5, int(math.sqrt(n)) + 1, 2):
            if n % i == 0:
                return False
    
        return True
    

Вот мой сценарий для сравнения вариантов:

import math
import pandas as pd
import seaborn as sns
import time
from matplotlib import pyplot as plt


def is_prime_1(n):
    ...
def is_prime_2(n):
    ...
def is_prime_3(n):
    ...
def is_prime_4(n):
    ...

default_func_list = (is_prime_1, is_prime_2, is_prime_3, is_prime_4)

def assert_equal_results(func_list=default_func_list, n):
    for i in range(-2, n):
        r_list = [f(i) for f in func_list]
        if not all(r == r_list[0] for r in r_list):
            print(i, r_list)
            raise ValueError
    print('all functions return the same results for integers up to {}'.format(n))

def compare_functions(func_list=default_func_list, n):
    result_list = []
    n_measurements = 3

    for f in func_list:
        for i in range(1, n + 1):
            ret_list = []
            t_sum = 0
            for _ in range(n_measurements):
                t_start = time.perf_counter()
                is_prime = f(i)
                t_end = time.perf_counter()

                ret_list.append(is_prime)
                t_sum += (t_end - t_start)

            is_prime = ret_list[0]
            assert all(ret == is_prime for ret in ret_list)
            result_list.append((f.__name__, i, is_prime, t_sum / n_measurements))

    df = pd.DataFrame(
        data=result_list,
        columns=['f', 'number', 'is_prime', 't_seconds'])
    df['t_micro_seconds'] = df['t_seconds'].map(lambda x: round(x * 10**6, 2))
    print('df.shape:', df.shape)

    print()
    print('', '-' * 41)
    print('| {:11s} | {:11s} | {:11s} |'.format(
        'is_prime', 'count', 'percent'))
    df_sub1 = df[df['f'] == 'is_prime_1']
    print('| {:11s} | {:11,d} | {:9.1f} % |'.format(
        'all', df_sub1.shape[0], 100))
    for (is_prime, count) in df_sub1['is_prime'].value_counts().iteritems():
        print('| {:11s} | {:11,d} | {:9.1f} % |'.format(
            str(is_prime), count, count * 100 / df_sub1.shape[0]))
    print('', '-' * 41)

    print()
    print('', '-' * 69)
    print('| {:11s} | {:11s} | {:11s} | {:11s} | {:11s} |'.format(
        'f', 'is_prime', 't min (us)', 't mean (us)', 't max (us)'))
    for f, df_sub1 in df.groupby(['f', ]):
        col = df_sub1['t_micro_seconds']
        print('|{0}|{0}|{0}|{0}|{0}|'.format('-' * 13))
        print('| {:11s} | {:11s} | {:11.2f} | {:11.2f} | {:11.2f} |'.format(
            f, 'all', col.min(), col.mean(), col.max()))
        for is_prime, df_sub2 in df_sub1.groupby(['is_prime', ]):
            col = df_sub2['t_micro_seconds']
            print('| {:11s} | {:11s} | {:11.2f} | {:11.2f} | {:11.2f} |'.format(
                f, str(is_prime), col.min(), col.mean(), col.max()))
    print('', '-' * 69)

    return df

Запустив функцию compare_functions(n=10**5) (числа до 100.000), я получаю следующий результат:

df.shape: (400000, 5)

 -----------------------------------------
| is_prime    | count       | percent     |
| all         |     100,000 |     100.0 % |
| False       |      90,408 |      90.4 % |
| True        |       9,592 |       9.6 % |
 -----------------------------------------

 ---------------------------------------------------------------------
| f           | is_prime    | t min (us)  | t mean (us) | t max (us)  |
|-------------|-------------|-------------|-------------|-------------|
| is_prime_1  | all         |        0.57 |        2.50 |      154.35 |
| is_prime_1  | False       |        0.57 |        1.52 |      154.35 |
| is_prime_1  | True        |        0.89 |       11.66 |       55.54 |
|-------------|-------------|-------------|-------------|-------------|
| is_prime_2  | all         |        0.24 |        1.14 |      304.82 |
| is_prime_2  | False       |        0.24 |        0.56 |      304.82 |
| is_prime_2  | True        |        0.25 |        6.67 |       48.49 |
|-------------|-------------|-------------|-------------|-------------|
| is_prime_3  | all         |        0.20 |        0.95 |       50.99 |
| is_prime_3  | False       |        0.20 |        0.60 |       40.62 |
| is_prime_3  | True        |        0.58 |        4.22 |       50.99 |
|-------------|-------------|-------------|-------------|-------------|
| is_prime_4  | all         |        0.20 |        0.89 |       20.09 |
| is_prime_4  | False       |        0.21 |        0.53 |       14.63 |
| is_prime_4  | True        |        0.20 |        4.27 |       20.09 |
 ---------------------------------------------------------------------

Затем, запустив функцию compare_functions(n=10**6) (числа до 1.000.000), я получаю следующий результат:

df.shape: (4000000, 5)

 -----------------------------------------
| is_prime    | count       | percent     |
| all         |   1,000,000 |     100.0 % |
| False       |     921,502 |      92.2 % |
| True        |      78,498 |       7.8 % |
 -----------------------------------------

 ---------------------------------------------------------------------
| f           | is_prime    | t min (us)  | t mean (us) | t max (us)  |
|-------------|-------------|-------------|-------------|-------------|
| is_prime_1  | all         |        0.51 |        5.39 |     1414.87 |
| is_prime_1  | False       |        0.51 |        2.19 |      413.42 |
| is_prime_1  | True        |        0.87 |       42.98 |     1414.87 |
|-------------|-------------|-------------|-------------|-------------|
| is_prime_2  | all         |        0.24 |        2.65 |      612.69 |
| is_prime_2  | False       |        0.24 |        0.89 |      322.81 |
| is_prime_2  | True        |        0.24 |       23.27 |      612.69 |
|-------------|-------------|-------------|-------------|-------------|
| is_prime_3  | all         |        0.20 |        1.93 |       67.40 |
| is_prime_3  | False       |        0.20 |        0.82 |       61.39 |
| is_prime_3  | True        |        0.59 |       14.97 |       67.40 |
|-------------|-------------|-------------|-------------|-------------|
| is_prime_4  | all         |        0.18 |        1.88 |      332.13 |
| is_prime_4  | False       |        0.20 |        0.74 |      311.94 |
| is_prime_4  | True        |        0.18 |       15.23 |      332.13 |
 ---------------------------------------------------------------------

Я использовал следующий сценарий для построения результатов:

def plot_1(func_list=default_func_list, n):
    df_orig = compare_functions(func_list=func_list, n=n)
    df_filtered = df_orig[df_orig['t_micro_seconds'] <= 20]
    sns.lmplot(
        data=df_filtered, x='number', y='t_micro_seconds',
        col='f',
        # row='is_prime',
        markers='.',
        ci=None)

    plt.ticklabel_format(style='sci', axis='x', scilimits=(3, 3))
    plt.show()
person Ralf    schedule 23.11.2018

В Python 3:

def is_prime(a):
    if a < 2:
        return False
    elif a!=2 and a % 2 == 0:
        return False
    else:
        return all (a % i for i in range(3, int(a**0.5)+1))

Пояснение: Простое число - это число, которое делится только на себя и 1. Пример: 2,3,5,7 ...

1) если a ‹2: если« a »меньше 2, это не простое число.

2) elif a! = 2 и a% 2 == 0: если «a» делится на 2, то это определенно не простое число. Но если a = 2, мы не хотим оценивать это, поскольку это простое число. Отсюда условие a! = 2

3) return all (a% i for i in range (3, int (a 0.5) +1)): ** Сначала посмотрите, что делает команда all () в Python. Начиная с 3, делим "a" до квадратного корня (a ** 0,5). Если "a" делится, вывод будет ложным. Почему квадратный корень? Скажем, а = 16. Квадратный корень из 16 = 4. Нам не нужно вычислять до 15. Нам нужно только проверить до 4, чтобы сказать, что это не простое число.

Дополнительно: цикл для поиска всех простых чисел в диапазоне.

for i in range(1,100):
    if is_prime(i):
        print("{} is a prime number".format(i))
person Deep grewal    schedule 25.02.2018
comment
Чем это отличается от ответа Александра Шмыгелюка? (Оба пропускают шаг 2 в range()…) - person greybeard; 25.02.2018
comment
Если число четное, то оно не простое (исключая 2). Так что не нужно проверять четные числа. Это будет намного быстрее, если вы хотите получить простое число в пределах диапазона. Это прямо исключает четные числа. - person Deep grewal; 27.02.2018

Для больших чисел вы не можете просто наивно проверить, делится ли номер кандидата N ни на одно из чисел меньше sqrt (N). Доступны гораздо более масштабируемые тесты, такие как тест простоты Миллера-Рабина . Ниже у вас есть реализация на Python:

def is_prime(x):
    """Fast implementation fo Miller-Rabin primality test, guaranteed to be correct."""
    import math
    def get_sd(x):
        """Returns (s: int, d: int) for which x = d*2^s """
        if not x: return 0, 0
        s = 0
        while 1:
            if x % 2 == 0:
                x /= 2
                s += 1
            else:
                return s, x
    if x <= 2:
        return x == 2
    # x - 1 = d*2^s
    s, d = get_sd(x - 1)
    if not s:
        return False  # divisible by 2!
    log2x = int(math.log(x) / math.log(2)) + 1
    # As long as Riemann hypothesis holds true, it is impossible
    # that all the numbers below this threshold are strong liars.
    # Hence the number is guaranteed to be a prime if no contradiction is found.
    threshold = min(x, 2*log2x*log2x+1)
    for a in range(2, threshold):
        # From Fermat's little theorem if x is a prime then a^(x-1) % x == 1
        # Hence the below must hold true if x is indeed a prime:
        if pow(a, d, x) != 1:
            for r in range(0, s):
                if -pow(a, d*2**r, x) % x == 1:
                    break
            else:
                # Contradicts Fermat's little theorem, hence not a prime.
                return False
    # No contradiction found, hence x must be a prime.
    return True

Вы можете использовать его для поиска огромных простых чисел:

x = 10000000000000000000000000000000000000000000000000000000000000000000000000000
for e in range(1000):
    if is_prime(x + e):
        print('%d is a prime!' % (x + e))
        break

# 10000000000000000000000000000000000000000000000000000000000000000000000000133 is a prime!

Если вы тестируете случайные целые числа, возможно, вы захотите сначала проверить, делится ли номер кандидата на какое-либо из простых чисел меньше, чем, скажем, 1000, прежде чем позвонить Миллеру-Рабину. Это поможет вам отфильтровать очевидные непростые числа, такие как 10444344345.

person Piotr Dabkowski    schedule 09.02.2019
comment
Это тест Миллера. Тест Миллера-Рабина представляет собой вероятностную версию, в которой случайно выбранные основания проверяются до тех пор, пока не будет достигнута достаточная уверенность. Кроме того, тест Миллера напрямую зависит не от гипотезы Римана, а от Обобщенной гипотезы Римана (GRH) для квадратичных символов Дирикле (я знаю, что это непросто, но и не понимаю). Это означает, что потенциальное доказательство гипотезы Римана может даже не относиться к GRH и, следовательно, не доказать правильность теста Миллера. Конечно, будет еще хуже, если GRH будет опровергнута. - person Arne Vogel; 06.05.2019
comment
is_prime (7699) - ›TypeError: pow () 3-й аргумент не разрешен, если все аргументы не являются целыми числами - person Frederico Schardong; 02.06.2021

Python 3:

def is_prime(a):
    return a > 1 and all(a % i for i in range(2, int(a**0.5) + 1))
person Oleksandr Shmyheliuk    schedule 27.06.2017

Слишком поздно на вечеринку, но надеюсь, что это поможет. Это актуально, если вы ищете большие простые числа:

Для проверки больших нечетных чисел необходимо использовать тест Ферма и / или тест Миллера-Рабина.

В этих тестах используется модульное возведение в степень, что довольно дорого, для возведения в степень n бит вам потребуется как минимум n большое умножение int и n большое деление int. Это означает, что сложность модульного возведения в степень составляет O (n³).

Поэтому перед тем, как использовать крупнокалиберную артиллерию, вам нужно провести несколько пробных делений. Но не делайте этого наивно, есть способ сделать это быстро. Сначала умножьте столько простых чисел, сколько уместится в словах, которые вы используете для больших целых чисел. Если вы используете 32-битные слова, умножьте 3 * 5 * 7 * 11 * 13 * 17 * 19 * 23 * 29 = 3234846615 и вычислите наибольший общий делитель с числом, которое вы проверяете, используя алгоритм Евклида. После первого шага число уменьшается ниже размера слова и продолжается алгоритм без выполнения полных больших целочисленных делений. Если НОД! = 1, это означает, что одно из умноженных вами простых чисел делит число, так что у вас есть доказательство того, что оно не является простым. Затем продолжайте с 31 * 37 * 41 * 43 * 47 = 95041567 и так далее.

После того, как вы проверили несколько сотен (или тысяч) простых чисел таким образом, вы можете выполнить 40 раундов теста Миллера-Рабина, чтобы подтвердить, что число является простым, после 40 раундов вы можете быть уверены, что число простое, есть только 2 ^ -80 шансов, что оно нет (скорее у вас аппаратные неисправности ...).

person Calmarius    schedule 27.04.2018

У меня есть простая функция, которая работает до (2 ^ 61) -1 Здесь:

from math import sqrt
def isprime(num): num > 1 and return all(num % x for x in range(2, int(sqrt(num)+1)))

Пояснение:

Функцию all() можно переопределить следующим образом:

def all(variables):
    for element in variables:
        if not element: return False
    return True

Функция all() просто просматривает серию логических значений / чисел и возвращает False, если видит 0 или False.

Функция sqrt() просто извлекает квадратный корень из числа.

Например:

>>> from math import sqrt
>>> sqrt(9)
>>> 3
>>> sqrt(100)
>>> 10

Часть num % x возвращает остаток от числа / х.

Наконец, range(2, int(sqrt(num))) означает, что будет создан список, который начинается с 2 и заканчивается на int(sqrt(num)+1).

Для получения дополнительной информации о диапазоне посетите этот веб-сайт. !

Часть num > 1 просто проверяет, больше ли переменная num 1, потому что 1 и 0 не считаются простыми числами.

Надеюсь, это помогло :)

person WhyAreYouReadingThis    schedule 11.05.2018
comment
Пожалуйста, поспорите, насколько это the best алгоритм или даже хороший. - person greybeard; 11.05.2018
comment
@greybeard, большинство простых функций здесь не поднимаются до (2 ^ 31) -1 или занимают слишком много времени для больших чисел, но мой работает до (2 ^ 61) -1, поэтому вы можете проверить, является ли число простым с более широким диапазон чисел. - person WhyAreYouReadingThis; 14.05.2018

В Python:

def is_prime(n):
    return not any(n % p == 0 for p in range(2, int(math.sqrt(n)) + 1))

Более прямое преобразование из математического формализма в Python будет использовать all (n% p! = 0 ...), но это требует строгой оценки всех значений p. Версия не любая может завершиться досрочно, если будет найдено значение True.

person Vlad Bezden    schedule 22.05.2018
comment
Wrt all (n% p! = 0 ...), но это требует строгой оценки всех значений p - это неверно. any и all оба выйдут раньше. Таким образом, при первом p, где n % p равно 0, all выйдет. - person aneroid; 09.01.2019

лучший алгоритм для простых чисел javascript

 function isPrime(num) {
      if (num <= 1) return false;
      else if (num <= 3) return true;
      else if (num % 2 == 0 || num % 3 == 0) return false;
      var i = 5;
      while (i * i <= num) {
        if (num % i == 0 || num % (i + 2) == 0) return false;
        i += 6;
      }
      return true
    }
person Mahdi Pourrostam    schedule 23.06.2018

Простое число - это любое число, которое делится только на 1 и само себя. Все остальные числа называются составными.

Самый простой способ найти простое число - проверить, является ли введенное число составным числом:

    function isPrime(number) {
        // Check if a number is composite
        for (let i = 2; i < number; i++) {
            if (number % i === 0) {
                return false;
            }
        }
        // Return true for prime numbers
        return true;
    }

Программа должна разделить значение number на все целые числа от 1 до его значения. Если это число можно разделить поровну не только на единицу, но и само по себе, это составное число.

Начальное значение переменной i должно быть 2, потому что как простые, так и составные числа могут делиться на 1 поровну.

    for (let i = 2; i < number; i++)

Тогда i меньше number по той же причине. И простые, и составные числа могут делиться сами по себе поровну. Поэтому нет причин проверять это.

Затем мы проверяем, можно ли разделить переменную поровну, используя оператор остатка.

    if (number % i === 0) {
        return false;
    }

Если остаток равен нулю, это означает, что number можно разделить поровну, следовательно, это составное число и возвращается false.

Если введенное число не соответствует условию, это означает, что это простое число, и функция возвращает истину.

person Community    schedule 27.07.2019
comment
(Хотя я думаю, simplest одна правильная интерпретация best :) Вопрос в том, Каков наилучший алгоритм проверки того, является ли число простым?: является ли проверка на делимость, где number / 2 < i < number выгодно ? А что насчет number < i*i? Что говорят понятные из остальных 3³ ответов? - person greybeard; 27.07.2019
comment
Для ясности: 1 не является ни простым , ни составным. И простые числа берутся из положительных целых чисел. - person paxdiablo; 13.05.2021

Позвольте предложить вам идеальное решение для 64-битных целых чисел. Извините за использование C #. Вы еще не указали его как python в своем первом посте. Надеюсь, вы сможете найти простую функцию modPow и легко ее проанализировать.

public static bool IsPrime(ulong number)
{
    return number == 2 
        ? true 
        : (BigInterger.ModPow(2, number, number) == 2 
            ? ((number & 1) != 0 && BinarySearchInA001567(number) == false) 
            : false)
}

public static bool BinarySearchInA001567(ulong number)
{
    // Is number in list?
    // todo: Binary Search in A001567 (https://oeis.org/A001567) below 2 ^ 64
    // Only 2.35 Gigabytes as a text file http://www.cecm.sfu.ca/Pseudoprimes/index-2-to-64.html
}
person Ayhan ARICAN    schedule 19.07.2020

Самая маленькая память? Это не самое маленькое, но шаг в правильном направлении.

class PrimeDictionary {
    BitArray bits;

    public PrimeDictionary(int n) {
        bits = new BitArray(n + 1);
        for (int i = 0; 2 * i + 3 <= n; i++) {
            bits.Set(i, CheckPrimality(2 * i + 3));
        }
    }

    public PrimeDictionary(IEnumerable<int> primes) {
        bits = new BitArray(primes.Max());
        foreach(var prime in primes.Where(p => p != 2)) {
            bits.Set((prime - 3) / 2, true);
        }
    }

    public bool IsPrime(int k) {
        if (k == 2) {
            return true;
        }
        if (k % 2 == 0) {
            return false;
        }
        return bits[(k - 3) / 2];
    }
}

Конечно, вы должны указать определение CheckPrimality.

person jason    schedule 26.11.2009

Я думаю, что одним из самых быстрых является мой метод.

void prime(long long int number) {
    // Establishing Variables
    long long int i = 5;
    int w = 2;
    const long long int lim = sqrt(number);

    // Gets 2 and 3 out of the way
    if (number == 1) { cout << number << " is hard to classify. \n";  return; }
    if (number == 2) { cout << number << " is Prime. \n";  return; }
    if (number == 3) { cout << number << " is Prime. \n";  return; }

    // Tests Odd Ball Factors
    if (number % 2 == 0) { cout << number << " is not Prime. \n";  return; }
    if (number % 3 == 0) { cout << number << " is not Prime. \n";  return; }

    while (i <= lim) {
        if (number % i == 0) { cout << number << " is not Prime. \n";  return; }
        // Tests Number
        i = i + w; // Increments number
        w = 6 - i; // We already tested 2 and 3
        // So this removes testing multepules of this
    }
    cout << number << " is Prime. \n"; return;
}
person Spl1ce    schedule 01.08.2017
comment
ошибка может быть ... 6 - i? - person Hmmm; 14.12.2017

Идея аналогична упомянутому алгоритму AKS.

public static boolean isPrime(int n) {

    if(n == 2 || n == 3) return true;
    if((n & 1 ) == 0 || n % 3 == 0) return false;
    int limit = (int)Math.sqrt(n) + 1;
    for(int i = 5, w = 2; i <= limit; i += w, w = 6 - w) {
        if(n % i == 0) return false;
        numChecks++;
    }
    return true;
}
person Derri Leahy    schedule 14.08.2017
comment
Не имеет отношения к алгоритму AKS. - person greybeard; 03.02.2018
comment
В цикле for вам не нужно проверять i ‹= limit, достаточно проверить i‹ limit. Таким образом, на каждой итерации вы делаете на одно сравнение меньше. - person Andrushenko Alexander; 12.07.2018

Чтобы узнать, является ли число или числа в диапазоне простыми / простыми.

#!usr/bin/python3

def prime_check(*args):
    for arg in args:
        if arg > 1:     # prime numbers are greater than 1
            for i in range(2,arg):   # check for factors
                if(arg % i) == 0:
                    print(arg,"is not Prime")
                    print(i,"times",arg//i,"is",arg)
                    break
            else:
                print(arg,"is Prime")
                
            # if input number is less than
            # or equal to 1, it is not prime
        else:
            print(arg,"is not Prime")
    return
    
# Calling Now
prime_check(*list(range(101)))  # This will check all the numbers in range 0 to 100 
prime_check(#anynumber)         # Put any number while calling it will check.
person Harsh Singh    schedule 23.03.2018
comment
Запустите этот код, он будет работать как для списка, так и для определенного числа - person Harsh Singh; 23.03.2018

Вы можете попробовать что-то вроде этого.

def main():
    try:
        user_in = int(input("Enter a number to determine whether the number is prime or not: "))
    except ValueError:
        print()
        print("You must enter a number!")
        print()
        return
    list_range = list(range(2,user_in+1))
    divisor_list = []
    for number in list_range:
        if user_in%number==0:
            divisor_list.append(number)
    if len(divisor_list) < 2:
        print(user_in, "is a prime number!")
        return
    else:
        print(user_in, "is not a prime number!")
        return
main()
person Patrick Jane    schedule 30.09.2018
comment
Это ужасное решение для проверки простоты. Как только вы найдете один делитель, вы узнаете ответ, но этот код находит все делители и затем принимает решение! И он игнорирует запрос OP на логический предикат, поскольку он всегда возвращает None. - person cdlane; 01.10.2018
comment
@cdlane, я знаю, что это не логическая функция возврата, я все еще новичок в Python и знаю, что это не идеально, в любом случае спасибо за комментарий - person Patrick Jane; 02.10.2018

Большинство предыдущих ответов верны, но вот еще один способ проверить, является ли число простым. Напоминаем, что простые числа - это целые числа больше 1, единственными делителями которых являются 1 и само себя. (источник)

Решение:

Обычно вы можете создать цикл и начать тестирование своего числа, чтобы увидеть, делится ли оно на 1,2,3 ... вплоть до числа, которое вы тестируете ... и т. Д., Но чтобы сократить время проверки, вы можете разделить свое число на половина значения вашего числа, потому что число не может делиться на что-либо, превышающее половину его значения. Например, если вы хотите, чтобы 100 было простым числом, вы можете перебирать до 50.

Фактический код:

def find_prime(number):
    if(number ==1):
        return False
    # we are dividiing and rounding and then adding the remainder to increment !
    # to cover not fully divisible value to go up forexample 23 becomes 11
    stop=number//2+number%2
    #loop through up to the half of the values
    for item in range(2,stop):
        if number%item==0:
           return False
        print(number)
    return True


if(find_prime(3)):
    print("it's a prime number !!")
else:
    print("it's not a prime")  
person grepit    schedule 26.10.2018
comment
Вам нужно только проверить квадратный корень числа, который немного меньше половины числа. Например. для n = 100 вам нужно проверить только 10, а не 50. Почему? В точном квадратном корне два множителя равны. Для любого другого фактора один будет меньше sqrt (n), а другой больше. Так что, если мы не видели ни одного к моменту проверки до sqrt (n) включительно, мы не найдем ни одного после. - person DanaJ; 24.01.2019

Мы можем использовать потоки Java, чтобы реализовать это за O (sqrt (n)); Учтите, что noneMatch - это метод shortCircuiting, который останавливает операцию, когда считает ее ненужной для определения результата:

Scanner in = new Scanner(System.in);
int n = in.nextInt();
System.out.println(n == 2 ? "Prime" : IntStream.rangeClosed(2, ((int)(Math.sqrt(n)) + 1)).noneMatch(a -> n % a == 0) ? "Prime" : "Not Prime");
person alirezafnatica    schedule 26.10.2018

С помощью потоков и лямбда-выражений Java-8 это можно реализовать всего за несколько строк:

public static boolean isPrime(int candidate){
        int candidateRoot = (int) Math.sqrt( (double) candidate);
        return IntStream.range(2,candidateRoot)
                .boxed().noneMatch(x -> candidate % x == 0);
    }

Производительность должна быть близка к O (sqrt (N)). Может кому пригодится.

person Stefan Repcek    schedule 29.10.2018
comment
range следует заменить на rangeClosed, чтобы включить кандидатаRoot. Также должен быть рассмотрен случай кандидата ‹2. - person udalmik; 27.01.2019
comment
Чем это отличается от предыдущего ответа alirezafnatica? - person greybeard; 28.07.2019

Вот мой ответ:

def isprime(num):
    return num <= 3 or (num + 1) % 6 == 0 or (num - 1) % 6 == 0

Функция вернет True, если какое-либо из свойств ниже True. Эти свойства математически определяют, что такое простое число.

  1. Число меньше или равно 3
  2. Число +1 делится на 6
  3. Число - 1 делится на 6
person Richie Bendall    schedule 23.01.2019
comment
>>> isprime(25) возвращает True. Вы проверяете очень простое необходимое условие (делимость на 2 или 3), но этого не достаточно. - person DanaJ; 24.01.2019
comment
Отлично, вы соответствуете этому свойству: каждое простое число больше 3 имеет форму 6n + 1 или 6n + 5, но существуют числа (например, 25), которые имеют форму 6n + 1 или 6n + 5, но они не простые - person Luis Felipe; 27.06.2020

bool isPrime(int n) {
if(n <= 3)
    return (n > 1)==0? false: true;
else if(n%2 == 0 || n%3 == 0)
    return false;

int i = 5;

while(i * i <= n){
    if(n%i == 0 || (n%(i+2) == 0))
        return false;
    i = i + 6;
}

return true;
}

Для любого числа минимальное количество итераций для проверки того, является ли число простым или нет, может составлять от 2 до квадратного корня из числа. Чтобы еще больше сократить количество итераций, мы можем проверить, делится ли число на 2 или 3, поскольку максимальное число можно исключить, проверив, делится ли число на 2 или 3. Кроме того, любое простое число больше 3 может быть выражено как 6k +1 или 6к-1. Таким образом, итерация может идти от 6k + 1 до квадратного корня из числа.

person Satyam Anand    schedule 22.07.2020
comment
Было бы лучше, если бы вы добавили пояснения к своему ответу с помощью редактирования. Многим читателям может быть непонятно, почему ваш ответ хороший, и они могли бы поучиться у вас, если бы вы объяснили больше. - person Brian Tompsett - 汤莱恩; 22.07.2020

Вот самый быстрый способ сделать это:

def divisors(integer):
    result = []
    i = 2 
    j = integer/2
    while(i <= j):
        if integer % i == 0:
            result.append(i)
            if i != integer//i:
                result.append(integer//i)
        i += 1
        j = integer//i
    if len(result) > 0:
        return sorted(result)
    else:
        return f"{integer} is prime"
person user3709120    schedule 01.01.2021

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

def isprime(n):
    if n%2==0:
        return n==2
    else:
        cota = int(n**0.5)+1
        for ind in range(3,2,cota):
            if n%ind==0:
                print(ind)
                return False
    is_one = n==1
    return True != is_one

isprime(22783)
  • Последний True != n==1 - избежать случая n=1.
person Luis Felipe    schedule 27.06.2020

Первое правило простого числа: если деление на 2 дает целое число или целое число Нет, это не простое число.

Самый быстрый способ узнать, используя любой компьютерный язык, - это сопоставление типов с использованием строк, а не математики. Сопоставьте DOT в струнном поплавке.

  • Разделите его на 2 ,,, n = n / 2
  • Преобразуйте это в строку ,,, n = строка (n)
  • если "." in n: {printf "Да, я премьер!"
    }
person rodeone2    schedule 07.01.2019
comment
Первое правило простого числа состоит в том, что если любое целое число больше единицы делит его, то это не простое число. Тестировать всего двумя - недостаточно. И преобразование числа в строку, чтобы проверить, является ли оно целым числом, возможно, самый медленный метод, который вы могли бы разумно придумать. - person JJJ; 07.01.2019

person    schedule
comment
Когда вы пишете ответ, даже если он правильный, пожалуйста, также немного объясните, что вы делаете и почему. Так люди, читающие ваш ответ, смогут легче понять, что вы решили. Спасибо! - person kim; 27.03.2018
comment
Конечно, Ким, спасибо, что указали на это. Это моя первая программа в Stackoverflow, впредь я буду добавлять соответствующие комментарии и пояснения. - person DKB; 28.03.2018

person    schedule
comment
Как мы узнаем, что это самый компактный алгоритм? - person ryanwebjackson; 04.07.2021