Як створити найбільш компактне відображення n → isprime (n) до межі N?


152

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

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

Як вирішити проблему?


3
Ваш запит трохи розпливчастий. Ви даєте підпис, який тестує одне число, але потім запитуєте структуру даних (1, N]. Чи хочете ви алгоритм, який генерує словник <int, bool> або лише функцію одного удару, яка перевіряє, чи є одне число первинна?
Michael Haren

@Michael Вибачте, це найкращий опис, з яким я міг прийти. На що я дивлюся, це явно, як ви говорите: булевий словник. Я хотів би мінімізувати простір словника. Дякую :)
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 Ось ти, quora.com/…
Алан Донг,

6
Не було б краще , щоб обчислити sqrtз nрази і порівнюючи iз ним, а не розрахунком i * iкожного циклу циклу?
педрос

3
@Dschoni ... але ви не можете підійти до найшвидшої реалізації у полях коментарів, щоб поділитися з нами?
GreenAsJade

3
Це не вдається для числа 1 :(
Дам’ян Павліця

27

Найкращий метод, на мою думку, - використовувати те, що пішло раніше.

В Інтернеті є списки перших Nпраймерів, які Nрозтягуються на щонайменше п’ятдесят мільйонів . Завантажте файли та використовуйте їх, ймовірно, це буде набагато швидше, ніж будь-який інший метод, який ви знайдете.

Якщо ви хочете , фактичний алгоритм для створення ваших власних простих чисел, Вікіпедія має всі види хороші речі на прості числа тут , в тому числі посилання на різні методи робити це, і прем'єр - тестування тут , як розподіл усіх і швидко детермінованих методів.

Слід докласти спільних зусиль, щоб знайти перший мільярд (а то й більше) прайсів та опублікувати їх десь у мережі, щоб люди могли перестати виконувати ту саму роботу знову і знову та ... :-)


2
@hamedbh: Цікаво. Ви намагалися завантажити ці файли? Здається, їх не існує.
paxdiablo

Ще не боюся: я просто швидко дивився під час обідньої перерви. Я видалю це посилання, якщо в ньому є щось шкідливе. Так вибачте, я справді повинен був це перевірити спочатку.
Хамед

1
Такі списки роблять існує. Я бачив їх років тому, але ніколи не переймався їх завантаженням. Правда в тому, що вони займають багато місця (відносно кажучи), і не повинні включатись у програми, які продає чи розповсюджує. Крім того, вони завжди і назавжди будуть неповними. Це має сенс перевіряти кожне число, що з’являється на практиці під час використання програм, оскільки настільки менше тестується таким чином, ніж довжина будь-якого списку, який ви можете мати. Крім того, я думаю, що Pax не розуміє, що мета головних алгоритмів, більшість часу, полягає в тестуванні ефективності / швидкості, а не в знаходженні простих чисел.
CogitoErgoCogitoSum

2
@CogitoErgoCogitoSum, погодьтеся, що список усіх праймів назавжди застаріє, оскільки я бачив математичний доказ того, що їх кількість нескінченна. Однак список перших x
праймерів

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

це лише реалізація c ++ вищезазначеного алгоритму 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 (ви можете протестувати з більшими цифрами, використовуючи мій код нижче).

Цей перший графік порівнює функції (які пояснюються далі у моїй відповіді), показуючи, що останні функції не зростають так швидко, як перші при збільшенні чисел.

сюжет1

І на другому сюжеті ми бачимо, що у випадку простих чисел час постійно зростає, але непрості числа не зростають з часом так швидко (адже більшість із них можна усунути на ранніх термінах).

сюжет2

Ось функції, які я використав:

  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)пам'яті - тому це досить непогане місце для початку, якщо ви не проходите тестування на особливо велику кількість.


Вибачте, я знаю, що мій опис неясний, я не дивлюсь на ДП :) подивіться на мій коментар @Michael
AraK

6

Можна використовувати симпатію .

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, ми не хочемо оцінювати це як просте число. Звідси умова a! = 2

3) повернути всі (a% 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) для квадратичних персонажів Діріклета (я знаю, що це рот, і я його теж не розумію). Це означає, що потенційний доказ гіпотези Рімана може навіть не застосовуватися до GRH, а отже, і не доводити тест Міллера правильним. Ще гірший випадок, звичайно, буде, якщо ОРГ буде спростовано.
Арне Фогель

2

Шлях занадто пізно на вечірку, але сподіваюся, що це допомагає. Це актуально, якщо ви шукаєте великих праймерів:

Для тестування великих непарних чисел потрібно використовувати тест Ферма та / або тест Міллера-Рабіна.

У цих тестах використовується модульна експоненція, що є досить дорогим, для nекспонації бітів потрібно принаймні nвелике множення int та nвелике поділ 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 Primes

 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його можна розділити рівномірно, отже, це складене число і повертати помилкове.

Якщо введене число не відповідало умові, це означає, що це просте число, і функція повертає істинне.


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 або 6k-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 <межа". Тож у кожній ітерації ви робите одне порівняння менше.
Андрушенко Олександр

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 відтепер я додам відповідні коментарі та пояснення.
ДКБ

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

Це жахливе рішення для тестування першості. Як тільки ви знайдете одного дільника, ви знаєте відповідь, але цей код знаходить усіх дільників і тоді приймає рішення! І він ігнорує запит ОП на булевий предикат, оскільки він завжди повертається 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 - це метод короткого кругообігу, який зупиняє операцію, коли визначить непотрібним для визначення результату:

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", щоб включити kandidatRoot. Також слід опрацювати кандидатуру <2 випадку.
udalmik

Чим це відрізняється від попередньої відповіді alirezafnatica ?
сіра борода

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.