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


152

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

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

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


3
Ваш запрос немного расплывчатый. Вы даете подпись, которая проверяет одно число, но затем запрашивает структуру данных (1, N]. Хотите ли вы алгоритм, который генерирует словарь <int, bool>, или просто однократную функцию, которая проверяет, является ли одно число главное?
Майкл Харен

@ Майкл Извините, это лучшее описание, которое я могу придумать. То, что я ищу, точно так же, как вы говорите: булев словарь. Я хотел бы минимизировать пространство словаря. Спасибо :)
AraK

1
Если это то, что вы ищете, его уже спросили: stackoverflow.com/questions/1032427/…
Ben S

14
Вы должны спросить АНБ
Чарльз Бретана

Ответы:


79

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

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

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


4
Миллер-Рабин является популярным быстрым вероятностным тестом, с которого можно начать.
QWR

214

Самый быстрый алгоритм для общего простого тестирования - 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))), я предварительно вычисляю ложные срабатывания (см. Числа Кармайкла ) и выполняю двоичный поиск. Это, безусловно, самый быстрый тест, который я когда-либо проводил, единственным недостатком является то, что диапазон ограничен.


7
Два вопроса: Можете ли вы объяснить лучше, что переменные iи wесть, и что подразумевается под формой 6k-1и 6k+1? Спасибо за ваше понимание и пример кода (который я пытаюсь понять)
Freedom_Ben

6
@Freedom_Ben Вот, пожалуйста
Алан Донг

6
Не было бы лучше , чтобы вычислить sqrtиз nраза и сравнивая iс ним, а не расчетом i * iкаждого цикла цикла?
Педрос

3
@Dschoni ... но вы не можете разместить самую быструю реализацию в полях комментариев здесь, чтобы поделиться с нами?
GreenAsJade

3
Это не
подходит

27

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

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

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

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


2
@hamedbh: Интересно. Вы пытались скачать эти файлы? Похоже, они не существуют.
paxdiablo

Боюсь, пока нет: я просто смотрел быстро во время обеденного перерыва. Я удалю эту ссылку на случай, если в ней будет что-то плохое. Извините, я действительно должен был проверить это первым.
Хамед

1
Такие списки делают существует. Я видел их много лет назад, но никогда не пытался их скачать. Правда в том, что они занимают много места (условно говоря) и не должны включаться в программы, которые продаются или распространяются. Кроме того, они всегда и навсегда будут неполными. В некотором смысле имеет смысл проверять каждое число, которое появляется на практике во время использования программ, поскольку таким образом будет проверено гораздо меньше, чем длина любого списка, которым вы можете владеть. Кроме того, я думаю, что pax не понимает, что цель простых алгоритмов, в большинстве случаев, заключается в тестировании эффективности / скорости, а не в нахождении простых чисел.
CogitoErgoCogitoSum

2
@CogitoErgoCogitoSum, согласитесь, что список всех простых чисел будет вечно устаревшим, так как я видел математическое доказательство того, что их число бесконечно. Тем не менее, список первых xпростых чисел будет вряд ли будет неполным , когда он построен :-)
paxdiablo

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

10
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;
}

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


1
Да, это один из самых эффективных детерминированных алгоритмов, но это не реализация AKS. Система AKS намного новее, чем описанный алгоритм. Возможно, он более эффективен, но его несколько сложно реализовать, в частности, из-за потенциально астрономически больших факториальных / биномиальных коэффициентов.
CogitoErgoCogitoSum

Чем это отличается от (не) ответа Дерри Лихи (кроме C вместо Java)? Как это ответ What is the algorithm that produces a data structure with lowest memory consumption for the range (1, N]?
седая борода

1
Как (n% i == 0 || n% (i + 2) == 0) соответствует 6n + 1 и 6n-1?
января

@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 *.
седобородый

Также обратите внимание, что этот алгоритм не дает правильный результат для 5и 7.
Атан Кларк

7

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

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

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()

6

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


Извините, я знаю, что мое описание расплывчато, я не смотрю на SOE :) посмотрите на мой комментарий @Michael
AraK

6

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

import sympy

sympy.ntheory.primetest.isprime(33393939393929292929292911111111)

True

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


Алгоритм - это последовательность четко определенных шагов, которые определяют абстрактное решение проблемы. - Какова мыслимая последовательность шагов в представленном коде? Что это memory consumption?
седобородый

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

6

В 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, мы не хотим оценивать это, поскольку это простое число. Отсюда условие а! = 2

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

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

for i in range(1,100):
    if is_prime(i):
        print("{} is a prime number".format(i))

1
Чем это отличается от ответа Александра Шмйелюка ? (Оба пропускают "шаг 2" в range()...)
Седобородый

1
Если число четное, то оно не простое (исключая 2). Так что не нужно проверять четные числа. Это будет намного быстрее, если вы хотите получить простое число в диапазоне. Это будет прямо исключать четные числа.
Глубокий рост


3

Для больших чисел вы не можете просто наивно проверить, делится ли число кандидатов 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.


Это тест Миллера. Тест Миллера-Рабина является вероятностным вариантом, в котором случайно выбранные основания проверяются до тех пор, пока не будет достигнута достаточная достоверность. Кроме того, критерий Миллера напрямую зависит не от гипотезы Римана, а от обобщенной гипотезы Римана (ГРГ) для квадратичных символов Дирихле (я знаю, что это глоток, и я тоже не понимаю его). Это означает, что потенциальное доказательство гипотезы Римана может даже не относиться к GRH, и, следовательно, не доказать правильность теста Миллера. Еще худший случай был бы, конечно, если бы ГРГ была опровергнута.
Арне Фогель

2

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

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

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

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

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


1

У меня есть простая функция, которая работает до (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()Функция просто проходит через ряд BOOLS / чисел и возвращает , Falseесли он видит 0 илиFalse .

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

Например:

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

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

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

Для получения дополнительной информации о ассортименте, посмотрите на этот сайт !

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

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


Пожалуйста, спорьте, как это the bestалгоритм, или даже хороший .
седобородый

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

1

В Python:

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

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


Wrt "all (n% p! = 0 ...), но это требует строгой оценки всех значений p" - это неверно. anyи allоба выйдут рано . Таким образом , на первый , pгде n % pнаходится 0, allбудет завершаться.
анероид

1

лучший алгоритм для простого числа 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
    }

1
import math
import time


def check_prime(n):

    if n == 1:
        return False

    if n == 2:
        return True

    if n % 2 == 0:
        return False

    from_i = 3
    to_i = math.sqrt(n) + 1

    for i in range(from_i, int(to_i), 2):
        if n % i == 0:
            return False
    return True

1

Простое число - это любое число, которое делится только на 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.

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


1
(Хотя я думаю, что simplestодна правильная интерпретация лучших :) Вопрос в том, что является лучшим алгоритмом для проверки, является ли число простым? : Выгодно ли проверять делимость number / 2 < i < number? Как насчет number < i*i? Что говорят понятные из других 3³ ответов?
глиняный кувшин

1

Позвольте мне предложить вам идеальное решение для 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
}

1
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 к квадратному корню из числа.


1
Было бы лучше, если бы вы добавили пояснение к своему ответу, используя редактирование . Многим читателям может быть непонятно, почему ваш ответ хороший, и они могли бы поучиться у вас, если бы вы объяснили больше.
Брайан Томпсетт - 莱恩 莱恩

0

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

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.


0

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

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;
}

1
ошибка может быть ... 6 - я?
Хммм

0

Схожая идея с алгоритмом 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;
}

1
Не имеет отношения к алгоритму AKS .
седобородый

В цикле for вам не нужно проверять «i <= limit», достаточно просто нажать «i <limit». Таким образом, в каждой итерации вы делаете одно сравнение меньше.
Андрушенко Александр

0

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

#!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.

Запустите этот код, он будет работать как для списка, так и для определенного числа
Harsh Singh

0
myInp=int(input("Enter a number: "))
if myInp==1:
    print("The number {} is neither a prime not composite no".format(myInp))
elif myInp>1:
    for i in range(2,myInp//2+1):
        if myInp%i==0:
            print("The Number {} is not a prime no".format(myInp))
            print("Because",i,"times",myInp//i,"is",myInp)
            break
    else:
        print("The Number {} is a prime no".format(myInp))
else:
    print("Alas the no {} is a not a prime no".format(myInp))

1
Когда вы пишете ответ, даже если он правильный, пожалуйста, напишите немного, объясняя, что вы делаете и почему. Таким образом, люди, читающие ваш ответ, могут легче понять, что вы решили. Спасибо!
Ким

1
Конечно, Ким, спасибо за указание на это. Это моя первая программа в Stackoverflow, отныне я буду добавлять соответствующие комментарии и объяснения.
DKB

0
public static boolean isPrime(int number) {
 if(number < 2)
   return false;
 else if(number == 2 || number == 3)
        return true;
      else {
        for(int i=2;i<=number/2;i++)
           if(number%i == 0)
             return false;
           else if(i==number/2)
                return true;
      }
    return false;
}

0

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

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()

Это ужасное решение для проверки первичности. Как только вы найдете один делитель, вы знаете ответ, но этот код находит все делители и затем решает! И он игнорирует запрос OP о булевом предикате, поскольку он всегда возвращается None.
cdlane

@cdlane я знаю, что это не булева функция возврата, я все еще новичок в python, и я знаю, что она не идеальна, спасибо за комментирование в любом случае
Патрик Джейн,

0

Большинство предыдущих ответов верны, но вот еще один способ проверить, является ли число простым числом. Напомним, что простые числа - это целые числа, большие 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")  

Вам нужно только проверить квадратный корень из числа, которое немного меньше половины числа. Например, для n = 100 нужно проверить только до 10, а не 50. Почему? Точно квадратный корень, два фактора равны. Для любого другого фактора один будет меньше, чем sqrt (n), а другой больше. Так что, если мы не увидели один к тому времени, когда у нас будет проверка до и включая sqrt (n), мы не найдем один после.
DanaJ

0

Мы можем использовать потоки 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");

0

С помощью потоков и лямбд 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)) . Может быть, кто-то найдет это полезным.


«range» должен быть заменен на «rangeClosed» для включения в список кандидат. Также должен быть обработан случай кандидата <2.
Удалмик


0

Вот мой взгляд на ответ:

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

>>> isprime(25)возвращается True. Вы проверяете очень простое необходимое условие (делимость на 2 или 3), но этого недостаточно .
DanaJ

Хорошо, вы подходите по этому свойству: каждое простое число больше 3 имеет форму 6n + 1 или 6n + 5, но существуют числа (как 25), которые имеют форму 6n + 1 или 6n + 5, но они не просты
Луис Фелипе

0

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

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
        return True != n==1

isprime(22783)
  • Последнее True != n==1, чтобы избежать дела n=1.
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.