Làm thế nào để tạo ánh xạ nhỏ gọn nhất n → isprime (n) đến giới hạn N?


152

Đương nhiên, vì bool isprime(number)sẽ có một cấu trúc dữ liệu tôi có thể truy vấn.
Tôi xác định thuật toán tốt nhất , là thuật toán tạo ra cấu trúc dữ liệu với mức tiêu thụ bộ nhớ thấp nhất cho phạm vi (1, N], trong đó N là hằng số.
Chỉ là một ví dụ về những gì tôi đang tìm kiếm: Tôi có thể biểu diễn mọi số lẻ với một bit, ví dụ cho phạm vi số đã cho (1, 10], bắt đầu từ 3:1110

Các từ điển sau đây có thể được ép nhiều hơn, phải không? Tôi có thể loại bỏ bội số của năm với một số công việc, nhưng các số kết thúc bằng 1, 3, 7 hoặc 9 phải có trong mảng bit.

Làm thế nào để tôi giải quyết vấn đề?


3
Yêu cầu của bạn là một chút mơ hồ. Bạn đưa ra một chữ ký kiểm tra một số duy nhất nhưng sau đó yêu cầu cấu trúc dữ liệu của (1, N]. Bạn có muốn một thuật toán tạo từ điển <int, bool> hoặc chỉ một hàm một lần kiểm tra nếu một số duy nhất là số nguyên tố?
Michael Haren

@Michael Xin lỗi, đó là mô tả tốt nhất tôi có thể đến với. Những gì tôi đang tìm kiếm chính xác như bạn đang nói: một từ điển boolean. Tôi muốn giảm thiểu không gian của từ điển. Cảm ơn :)
AraK

1
Nếu đó là những gì bạn đang tìm kiếm nó được hỏi đã: stackoverflow.com/questions/1032427/...
Ben S

14
Bạn sẽ cần hỏi NSA
Charles Bretana

Câu trả lời:


79

Có nhiều cách để làm bài kiểm tra nguyên thủy .

Thực sự không có cấu trúc dữ liệu để bạn truy vấn. Nếu bạn có nhiều số để kiểm tra, có lẽ bạn nên chạy thử nghiệm xác suất vì những số đó nhanh hơn, và sau đó theo dõi nó bằng một bài kiểm tra xác định để đảm bảo số đó là số nguyên tố.

Bạn nên biết rằng toán học đằng sau các thuật toán nhanh nhất không dành cho người yếu tim.


4
Miller-Rabin là một thử nghiệm xác suất nhanh phổ biến để bắt đầu.
qwr

214

Thuật toán nhanh nhất để kiểm tra tổng quát là AKS . Bài viết Wikipedia mô tả nó ở độ dài và liên kết đến bài báo gốc.

Nếu bạn muốn tìm số lớn, hãy nhìn vào các số nguyên tố có dạng đặc biệt như số nguyên tố Mersenne .

Thuật toán tôi thường triển khai (dễ hiểu và mã) như sau (bằng 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

Đây là một biến thể của O(sqrt(N))thuật toán cổ điển . Nó sử dụng thực tế là một số nguyên tố (trừ 2 và 3) có dạng 6k - 1hoặc 6k + 1và chỉ nhìn vào các ước của dạng này.

Đôi khi, nếu tôi thực sự muốn tốc độ và phạm vi bị hạn chế , tôi thực hiện một bài kiểm tra giả dựa trên định lý nhỏ của Fermat . Nếu tôi thực sự muốn có nhiều tốc độ hơn (tức là tránh thuật toán O (sqrt (N)) hoàn toàn), tôi sẽ tính toán trước các giá trị dương (xem các số của Carmichael ) và thực hiện tìm kiếm nhị phân. Đây là thử nghiệm nhanh nhất tôi từng thực hiện, nhược điểm duy nhất là phạm vi bị giới hạn.


7
Hai câu hỏi sau: Bạn có thể giải thích rõ hơn những gì các biến iwđang có, và những gì có nghĩa là hình thức 6k-16k+1? Cảm ơn bạn đã hiểu biết của bạn và mẫu mã (mà tôi đang cố gắng hiểu)
Freedom_Ben

6
@Freedom_Ben Bạn đi đây, quora.com/ Từ
Alan Dong

6
Nó sẽ không thể tốt hơn để tính toán sqrtcủa nmột lần và so sánh ivới nó, chứ không phải là tính toán i * imỗi chu kỳ của vòng lặp?
pedros 18/05/2015

3
@Dschoni ... nhưng bạn không thể phù hợp với việc triển khai nhanh nhất trong các trường nhận xét ở đây để chia sẻ với chúng tôi?
GreenAsJade

3
Nó không thành công cho số 1 :(
Damjan Pavlica

27

Theo tôi, phương pháp tốt nhất là sử dụng những gì đã có trước đây.

Có danh sách các Nsố nguyên tố đầu tiên trên internet với Nsố lượng lên tới ít nhất năm mươi triệu . Tải xuống các tệp và sử dụng chúng, nó có thể sẽ nhanh hơn nhiều so với bất kỳ phương pháp nào khác mà bạn nghĩ ra.

Nếu bạn muốn có một thuật toán thực tế để tạo các số nguyên tố của riêng mình, Wikipedia có tất cả các loại công cụ tốt ở các số nguyên tố ở đây , bao gồm các liên kết đến các phương pháp khác nhau để thực hiện nó, và kiểm tra chính ở đây , cả phương pháp xác định nhanh và xác định nhanh.

Cần có một nỗ lực phối hợp để tìm ra các tỷ lệ đầu tiên (hoặc thậm chí nhiều hơn) và đưa chúng được xuất bản trên mạng ở đâu đó để mọi người có thể ngừng làm công việc này lặp đi lặp lại và ... :-)


2
@hamedbh: Thú vị. Bạn đã thử tải những tập tin đó chưa? Có vẻ như họ không tồn tại.
paxdiablo

Chưa hết, tôi sợ: tôi chỉ nhìn nhanh trong giờ nghỉ trưa. Tôi sẽ xóa liên kết đó trong trường hợp có bất cứ điều gì độc hại về nó. Xin lỗi, tôi thực sự nên kiểm tra nó trước.
Hamed

1
Danh sách như vậy không tồn tại. Tôi đã nhìn thấy chúng từ nhiều năm trước nhưng không bao giờ quan tâm để tải chúng. Sự thật là, chúng chiếm rất nhiều không gian (nói một cách tương đối) và không nên được đưa vào các chương trình mà người ta bán hoặc phân phối. Hơn nữa, chúng sẽ luôn luôn và mãi mãi không đầy đủ. Việc kiểm tra từng con số xuất hiện trong thực tế trong quá trình sử dụng chương trình sẽ có ý nghĩa hơn, vì sẽ ít được kiểm tra theo cách đó hơn độ dài của bất kỳ danh sách nào bạn có thể sở hữu. Ngoài ra, tôi nghĩ rằng pax không nhận ra mục đích của các thuật toán chính, hầu hết thời gian, là để kiểm tra hiệu quả / tốc độ hơn là thực sự tìm ra các số nguyên tố.
CogitoErgoCogitoSum

2
@CogitoErgoCogitoSum, đồng ý rằng danh sách tất cả các số nguyên tố sẽ mãi mãi bị lỗi thời kể từ khi tôi thấy bằng chứng toán học rằng chúng là vô hạn về số lượng. Tuy nhiên, danh sách các xsố nguyên tố đầu tiên sẽ khó có thể không đầy đủ khi được xây dựng :-)
paxdiablo

1
Đúng, nhưng có các phương pháp lưu trữ tốt hơn so với đọc từ tệp theo kiểu tuyến tính. Nếu bạn thực sự muốn đọc từ một tập hợp các số nguyên tố được tạo trước, hãy thử một cấu trúc dữ liệu phức tạp hơn để tăng tốc độ của vấn đề.
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;
}

đây chỉ là triển khai c ++ của thuật toán AKS ở trên


1
Đây là một trong những thuật toán xác định hiệu quả nhất mà tôi từng gặp, vâng, nhưng nó không phải là một triển khai của AKS. Hệ thống AKS mới hơn nhiều so với thuật toán được phác thảo. Nó được cho là hiệu quả hơn, nhưng hơi khó thực hiện, imo, dựa trên các hệ số yếu tố / nhị thức có khả năng thiên văn lớn.
CogitoErgoCogitoSum

Điều này khác với câu trả lời ( không phải) của Derri Leahi (khác với C thay vì Java) như thế nào? Làm thế nào để trả lời này What is the algorithm that produces a data structure with lowest memory consumption for the range (1, N]?
greybeard

1
Làm thế nào (n% i == 0 || n% (i + 2) == 0) tương ứng với 6n + 1 & 6n-1?
yesh

@YeshwanthVenkatesh: How does (n%i == 0 || n%(i+2) == 0) correspond to 6n+1 & 6n-1?một phần của câu trả lời là các vai trò khác nhau n, phần còn lại là 6n + 1 & 6n-1 tương đương với (6n-1) +0 & (6n-1) + 2 *.
greybeard

Cũng lưu ý rằng thuật toán này không cho kết quả chính xác cho 57.
Athan Clark

7

Tôi đã so sánh hiệu quả của các đề xuất phổ biến nhất để xác định xem một số có phải là số nguyên tố hay không. Tôi đã sử dụng python 3.6trên ubuntu 17.10; Tôi đã thử nghiệm với số lượng lên tới 100.000 (bạn có thể kiểm tra với số lượng lớn hơn bằng mã của tôi bên dưới).

Biểu đồ đầu tiên này so sánh các hàm (được giải thích sâu hơn trong câu trả lời của tôi), cho thấy các hàm cuối không tăng nhanh như hàm đầu tiên khi tăng số.

lô 1

Và trong âm mưu thứ hai, chúng ta có thể thấy rằng trong trường hợp số nguyên tố, thời gian tăng dần đều, nhưng số không nguyên tố không tăng quá nhanh theo thời gian (vì hầu hết chúng có thể bị loại bỏ sớm).

lô2

Dưới đây là các chức năng tôi đã sử dụng:

  1. câu trả lời nàycâu trả lời này gợi ý một cấu trúc sử dụng all():

    def is_prime_1(n):
        return n > 1 and all(n % i for i in range(2, int(math.sqrt(n)) + 1))
    
  2. Câu trả lời này đã sử dụng một số loại vòng lặp 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. Câu trả lời này bao gồm một phiên bản có forvòng lặp:

    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. Và tôi đã trộn một vài ý tưởng từ các câu trả lời khác thành một ý tưởng mới:

    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
    

Đây là kịch bản của tôi để so sánh các biến thể:

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

Chạy chức năng compare_functions(n=10**5)(số lượng lên tới 100.000) Tôi nhận được kết quả đầu ra này:

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

Sau đó, chạy chức năng compare_functions(n=10**6)(số lên tới 1.000.000) tôi nhận được kết quả đầu ra này:

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

Tôi đã sử dụng đoạn script sau để vẽ kết quả:

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

Người ta có thể sử dụng sympy .

import sympy

sympy.ntheory.primetest.isprime(33393939393929292929292911111111)

True

Từ tài liệu sympy. Bước đầu tiên là tìm kiếm các yếu tố tầm thường, nếu tìm thấy sẽ cho phép quay trở lại nhanh chóng. Tiếp theo, nếu sàng đủ lớn, sử dụng tìm kiếm chia đôi trên sàng. Đối với số lượng nhỏ, một tập hợp các thử nghiệm Miller-Rabin xác định được thực hiện với các cơ sở được biết là không có mẫu phản ứng trong phạm vi của chúng. Cuối cùng, nếu số lượng lớn hơn 2 ^ 64, thử nghiệm BPSW mạnh được thực hiện. Mặc dù đây là một thử nghiệm cơ bản có thể xảy ra và chúng tôi tin rằng các mẫu phản ứng tồn tại, không có mẫu nào được biết đến


Một thuật toán là một chuỗi các bước được xác định rõ ràng xác định một giải pháp trừu tượng cho một vấn đề. - trình tự các bước có thể hiểu được trong mã được trình bày là gì? Nó là memory consumption
greybeard

2
@greybeard. Từ tài liệu sympy. Bước đầu tiên là tìm kiếm các yếu tố tầm thường, nếu tìm thấy sẽ cho phép quay trở lại nhanh chóng. Tiếp theo, nếu sàng đủ lớn, sử dụng tìm kiếm chia đôi trên sàng. Đối với số lượng nhỏ, một tập hợp các thử nghiệm Miller-Rabin xác định được thực hiện với các cơ sở được biết là không có mẫu phản ứng trong phạm vi của chúng. Cuối cùng, nếu số lượng lớn hơn 2 ^ 64, thử nghiệm BPSW mạnh được thực hiện. Mặc dù đây là một thử nghiệm cơ bản có thể xảy ra và chúng tôi tin rằng các mẫu phản ứng tồn tại, không có mẫu phản ứng nào được biết đến.
LetzerWille

6

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

Giải thích: Số nguyên tố là một số chỉ chia hết cho chính nó và 1. Ví dụ: 2,3,5,7 ...

1) nếu a <2: nếu "a" nhỏ hơn 2 thì đó không phải là số nguyên tố.

2) elif a! = 2 và a% 2 == 0: nếu "a" chia hết cho 2 thì nó chắc chắn không phải là số nguyên tố. Nhưng nếu a = 2, chúng tôi không muốn đánh giá rằng đó là số nguyên tố. Do đó điều kiện a! = 2

3) trả về tất cả (a% i cho i trong phạm vi (3, int (a 0,5) +1)): ** Trước tiên hãy xem lệnh all () làm gì trong python. Bắt đầu từ 3, chúng tôi chia "a" cho đến căn bậc hai của nó (a ** 0,5). Nếu "a" chia hết thì đầu ra sẽ là Sai. Tại sao căn bậc hai? Hãy nói a = 16. Căn bậc hai của 16 = 4. Chúng ta không cần phải đánh giá đến 15. Chúng ta chỉ cần kiểm tra đến 4 để nói rằng đó không phải là số nguyên tố.

Thêm: Một vòng lặp để tìm tất cả các số nguyên tố trong một phạm vi.

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

1
Điều này khác với câu trả lời của Oleksandr Shmyheliuk như thế nào? (Cả hai đều bỏ lỡ "bước 2" trong trận đấu range())
greybeard

1
Nếu một số chẵn thì nó không phải là số nguyên tố (không bao gồm 2). Vì vậy, không cần phải kiểm tra số chẵn. Điều này sẽ nhanh hơn nhiều nếu bạn muốn có được số nguyên tố trong một phạm vi. Nó sẽ thẳng lên loại trừ các số chẵn.
Sâu lớn


3

Đối với các số lớn, bạn không thể đơn giản kiểm tra xem số ứng cử viên N có chia hết cho không có số nào nhỏ hơn sqrt (N) không. Có nhiều thử nghiệm có khả năng mở rộng hơn nhiều, chẳng hạn như thử nghiệm nguyên thủy Miller-Rabin . Dưới đây bạn đã thực hiện trong 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

Bạn có thể sử dụng nó để tìm số nguyên tố lớn:

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

# 10000000000000000000000000000000000000000000000000000000000000000000000000133 is a prime!

Nếu bạn đang kiểm tra các số nguyên ngẫu nhiên, trước tiên bạn có thể muốn kiểm tra xem số ứng cử viên có chia hết cho bất kỳ số nguyên tố nào nhỏ hơn không, giả sử 1000, trước khi bạn gọi Miller-Rabin. Điều này sẽ giúp bạn lọc ra các số nguyên tố không rõ ràng, chẳng hạn như 10444344345.


Đây là bài kiểm tra Miller. Thử nghiệm Miller-Rabin là phiên bản xác suất trong đó các cơ sở được chọn ngẫu nhiên được kiểm tra cho đến khi đạt được độ tin cậy đủ. Ngoài ra, bài kiểm tra Miller không phụ thuộc trực tiếp vào Giả thuyết Riemann, nhưng Giả thuyết Riemann tổng quát (GRH) cho các nhân vật Diriclet bậc hai (tôi biết đó là một câu cửa miệng và tôi cũng không hiểu nó). Điều đó có nghĩa là một bằng chứng tiềm năng cho Giả thuyết Riemann thậm chí có thể không áp dụng cho GRH, và do đó không chứng minh được thử nghiệm Miller đúng. Thậm chí trường hợp xấu hơn sẽ là tất nhiên nếu GRH bị từ chối.
Arne Vogel

2

Cách quá muộn cho bữa tiệc, nhưng hy vọng điều này sẽ giúp. Điều này có liên quan nếu bạn đang tìm kiếm các số nguyên tố lớn:

Để kiểm tra số lẻ lớn, bạn cần sử dụng thử nghiệm Fermat và / hoặc Miller-Rabin.

Các thử nghiệm này sử dụng lũy ​​thừa mô-đun khá tốn kém, đối với nlũy thừa bit, bạn cần ít nhất là nphép nhân nint lớn và phép chia int lớn. Có nghĩa là độ phức tạp của lũy thừa mô đun là O (n³).

Vì vậy, trước khi sử dụng những khẩu súng lớn, bạn cần thực hiện khá nhiều lần thử nghiệm. Nhưng đừng làm điều đó một cách ngây thơ, có một cách để làm chúng nhanh. Đầu tiên nhân nhiều số nguyên tố với nhau, nhiều số khớp với một từ bạn sử dụng cho các số nguyên lớn. Nếu bạn sử dụng các từ 32 bit, hãy nhân 3 * 5 * 7 * 11 * 13 * 17 * 19 * 23 * 29 = 3234846615 và tính toán ước số chung lớn nhất với số bạn kiểm tra bằng thuật toán Euclide. Sau bước đầu tiên, số được giảm xuống dưới kích thước từ và tiếp tục thuật toán mà không thực hiện hoàn thành các phép chia số nguyên lớn. Nếu GCD! = 1, điều đó có nghĩa là một trong những số nguyên tố bạn nhân với nhau sẽ chia số, vì vậy bạn có một bằng chứng không phải là số nguyên tố. Sau đó tiếp tục với 31 * 37 * 41 * 43 * 47 = 95041567, v.v.

Khi bạn đã kiểm tra hàng trăm (hoặc nghìn) số nguyên tố theo cách này, bạn có thể thực hiện 40 vòng kiểm tra Miller-Rabin để xác nhận số đó là số nguyên tố, sau 40 vòng, bạn có thể chắc chắn số đó là số nguyên tố chỉ có 2 ^ -80 cơ hội không (nhiều khả năng phần cứng của bạn bị trục trặc ...).


1

Tôi đã có một hàm số nguyên tố hoạt động cho đến khi (2 ^ 61) -1 Tại đây:

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

Giải trình:

Các all()chức năng có thể được xác định lại để này:

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

Các all()chức năng chỉ đi qua một loạt các bools / số và lợi nhuận Falsenếu nó thấy 0 hoặc False.

Các sqrt()chức năng chỉ được làm căn bậc hai của một số.

Ví dụ:

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

Phần num % xtrả về phần còn lại của num / x.

Cuối cùng, range(2, int(sqrt(num)))có nghĩa là nó sẽ tạo một danh sách bắt đầu từ 2 và kết thúc tạiint(sqrt(num)+1)

Để biết thêm thông tin về phạm vi, hãy xem trang web này !

Phần num > 1này chỉ kiểm tra xem biến numcó lớn hơn 1 hay không, vì 1 và 0 không được coi là số nguyên tố.

Tôi hy vọng điều này đã giúp :)


Vui lòng tranh luận làm thế nào đây là the bestthuật toán, hoặc thậm chí là một thuật toán tốt .
greybeard

@greybeard, Hầu hết các hàm số nguyên tố ở đây không tăng (2 ^ 31) -1 hoặc mất quá nhiều thời gian cho số cao, nhưng hàm của tôi hoạt động cho đến (2 ^ 61) -1, vì vậy bạn có thể kiểm tra xem một số có phải là số nguyên tố rộng hơn không phạm vi số.
WhyAreYouRead This

1

Trong Python:

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

Một chuyển đổi trực tiếp hơn từ hình thức toán học sang Python sẽ sử dụng tất cả (n% p! = 0 ...) , nhưng điều đó đòi hỏi phải đánh giá chặt chẽ tất cả các giá trị của p. Không phải phiên bản nào cũng có thể chấm dứt sớm nếu tìm thấy giá trị True.


Đã viết "tất cả (n% p! = 0 ...), nhưng điều đó đòi hỏi phải đánh giá chặt chẽ tất cả các giá trị của p" - điều đó không chính xác. anyallcả hai sẽ thoát sớm . Vì vậy, tại đầu tiên pn % p0, allsẽ thoát.
aneroid

1

thuật toán tốt nhất cho số 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

Số nguyên tố là bất kỳ số nào chỉ chia hết cho 1 và chính nó. Tất cả các số khác được gọi là tổng hợp .

Cách đơn giản nhất, để tìm số nguyên tố, là kiểm tra xem số đầu vào có phải là số tổng hợp không:

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

Chương trình phải chia giá trị của numbertất cả các số từ 1 trở lên cho đến giá trị của nó. Nếu số này có thể được chia đều không chỉ cho một và chính nó là số tổng hợp.

Giá trị ban đầu của biến iphải là 2 vì cả hai số nguyên tố và tổng hợp có thể chia đều cho 1.

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

Sau đó ilà ít hơn numbercho cùng một lý do. Cả hai số nguyên tố và tổng hợp có thể được chia đều cho chính chúng. Do đó không có lý do để kiểm tra nó.

Sau đó, chúng tôi kiểm tra xem biến có thể được chia đều hay không bằng cách sử dụng toán tử còn lại.

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

Nếu phần còn lại bằng 0, điều đó có nghĩa là numbercó thể chia đều, do đó là số tổng hợp và trả về sai.

Nếu số đã nhập không đáp ứng điều kiện, điều đó có nghĩa là số nguyên tố và hàm trả về đúng.


1
(Trong khi tôi nghĩ simplestmột cách giải thích hợp lệ là tốt nhất :) Câu hỏi đặt ra là thuật toán tốt nhất để kiểm tra xem một số có phải là số nguyên tố không? : Đang kiểm tra tính phân chia ở đâu number / 2 < i < numberthuận lợi? Thế còn number < i*i? Những câu trả lời dễ hiểu của 3³ câu trả lời khác nói gì?
greybeard

1

Hãy để tôi đề nghị bạn giải pháp hoàn hảo cho số nguyên 64 bit. Xin lỗi để sử dụng C #. Bạn chưa chỉ định nó là python trong bài viết đầu tiên của bạn. Tôi hy vọng bạn có thể tìm thấy một hàm modPow đơn giản và phân tích nó dễ dàng.

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

đối với bất kỳ số nào, số lần lặp tối thiểu để kiểm tra xem số đó có phải là số nguyên tố hay không có thể từ 2 đến căn bậc hai của số. Để giảm số lần lặp, thậm chí nhiều hơn, chúng ta có thể kiểm tra xem số đó có chia hết cho 2 hoặc 3 hay không vì số lượng tối đa có thể được loại bỏ bằng cách kiểm tra xem số đó có chia hết cho 2 hay không. Có thể biểu thị bất kỳ số nguyên tố nào lớn hơn 3 +1 hoặc 6k-1. Vì vậy, phép lặp có thể đi từ 6k + 1 đến căn bậc hai của số.


1
Sẽ tốt hơn nếu bạn thêm một số lời giải thích cho câu trả lời của mình bằng cách sử dụng chỉnh sửa . Nhiều người đọc có thể không rõ lý do tại sao câu trả lời của bạn là một câu hỏi hay và họ có thể học hỏi từ bạn nếu bạn giải thích thêm.
Brian Tompsett - 汤

0

Ký ức nhỏ nhất? Đây không phải là nhỏ nhất, nhưng là một bước đi đúng hướng.

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

Tất nhiên, bạn phải xác định định nghĩa của CheckPrimality.


0

Tôi nghĩ rằng một trong những cách nhanh nhất là phương pháp của tôi mà tôi đã thực hiện.

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
một lỗi có thể là ... 6 - i?
Hmmm

0

Ý tưởng tương tự như thuật toán AKS đã được đề cập

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
Không liên quan đến thuật toán AKS .
greybeard

Trong vòng lặp for bạn không cần kiểm tra "i <= giới hạn", nó đủ để ckeck "i <giới hạn". Vì vậy, trong mỗi lần lặp lại, bạn thực hiện một so sánh ít hơn.
Andrushenko Alexander

0

Để tìm xem số hoặc số trong một phạm vi là / là số nguyên tố.

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

Chạy mã này, nó sẽ hoạt động cho cả danh sách và số cụ thể
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
Khi bạn viết câu trả lời, ngay cả khi nó đúng, xin vui lòng viết một chút giải thích những gì bạn đang làm, và tại sao. Bằng cách này, mọi người đọc câu trả lời của bạn có thể nắm bắt dễ dàng hơn những gì bạn đã giải quyết. Cảm ơn bạn!
kim

1
Chắc chắn Kim, cảm ơn bạn đã chỉ ra điều đó. Đây là chương trình đầu tiên của tôi trong Stackoverflow do đó tôi sẽ thêm nhận xét và giải thích phù hợp.
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

Bạn có thể thử một cái gì đó như thế này.

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

Đây là một giải pháp khủng khiếp để thử nghiệm tính nguyên thủy. Khi bạn tìm thấy một ước số, bạn biết câu trả lời, nhưng mã này tìm tất cả các ước và sau đó quyết định! Và nó bỏ qua yêu cầu của OP về một vị từ boolean vì nó luôn trả về None.
cdlane

@cdlane Tôi biết đây không phải là hàm trả về boolean, tôi vẫn là người mới bắt đầu với python và tôi biết nó không hoàn hảo, cảm ơn vì đã bình luận bằng mọi cách
Patrick Jane

0

Hầu hết các câu trả lời trước đều đúng nhưng đây là một cách nữa để kiểm tra xem một số là số nguyên tố. Khi xem lại, số nguyên tố là số nguyên lớn hơn 1 với các yếu tố duy nhất là 1 và chính nó. ( Nguồn )

Giải pháp:

Thông thường, bạn có thể tạo một vòng lặp và bắt đầu kiểm tra số của mình để xem nó có chia hết cho 1,2,3 không ... cho đến số bạn đang kiểm tra ... vv nhưng để giảm thời gian kiểm tra, bạn có thể chia số của mình cho một nửa giá trị số của bạn bởi vì một số không thể chia chính xác cho bất cứ thứ gì trên một nửa giá trị của nó. Ví dụ nếu bạn muốn xem 100 là số nguyên tố bạn có thể lặp qua tối đa 50.

Mã thực tế :

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

Bạn chỉ cần kiểm tra căn bậc hai của số, nó nhỏ hơn một nửa số. Ví dụ: với n = 100 bạn chỉ cần kiểm tra đến 10 chứ không phải 50. Tại sao? Tại chính xác căn bậc hai, hai yếu tố bằng nhau. Đối với bất kỳ yếu tố nào khác, một yếu tố sẽ nhỏ hơn sqrt (n) và yếu tố khác lớn hơn. Vì vậy, nếu chúng ta chưa từng thấy một lần khi chúng ta kiểm tra và bao gồm cả sqrt (n), chúng ta sẽ không tìm thấy cái nào sau đó.
DanaJ

0

Chúng ta có thể sử dụng các luồng java để thực hiện điều này trong O (sqrt (n)); Hãy xem xét noneMatch là một phương thức ShortCircuiting dừng hoạt động khi thấy không cần thiết để xác định kết quả:

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

Với sự trợ giúp của các luồng Java-8 và lambdas, nó có thể được triển khai như thế này chỉ trong vài dòng:

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

Hiệu suất phải gần với O (sqrt (N)) . Có lẽ ai đó thấy nó hữu ích.


"phạm vi" nên được thay thế bằng "phạm vi" để bao gồm ứng cử viên. Ngoài ra ứng viên <2 trường hợp nên được xử lý.
udalmik

Điều này khác với câu trả lời trước của alirezafnatica như thế nào?
greybeard

0

Đây là câu trả lời của tôi:

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

Hàm sẽ trả về True nếu bất kỳ thuộc tính nào dưới đây là True. Những tính chất này xác định một cách toán học một nguyên tố là gì.

  1. Số lượng nhỏ hơn hoặc bằng 3
  2. Số + 1 chia hết cho 6
  3. Số - 1 chia hết cho 6

>>> isprime(25)trả lại True. Bạn đang kiểm tra một điều kiện cần thiết rất đơn giản (chia hết cho 2 hoặc 3) nhưng điều này là không đủ .
DanaJ

Thật tuyệt, bạn phù hợp với tính chất này: mọi số nguyên tố lớn hơn 3 đều có dạng 6n + 1 hoặc 6n + 5, nhưng tồn tại các số (như 25) có dạng 6n + 1 hoặc 6n + 5, nhưng chúng không phải là chính
Luis Felipe

0

Khi tôi phải xác minh nhanh, tôi viết mã đơn giản này dựa trên sự phân chia cơ bản giữa các số thấp hơn căn bậc hai của đầu vào.

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)
  • Việc cuối cùng True != n==1là tránh trường hợp n=1.
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.