วิธีสร้างการแม็พแบบกระชับที่สุด n → isprime (n) สูงสุดถึงขีด จำกัด N?


152

โดยธรรมชาติแล้วbool isprime(number)จะมีโครงสร้างข้อมูลที่ฉันสามารถสืบค้นได้
ฉันกำหนดอัลกอริธึมที่ดีที่สุดเพื่อเป็นอัลกอริธึมที่สร้างโครงสร้างข้อมูลที่มีการใช้หน่วยความจำต่ำสุดสำหรับช่วง (1, N] โดยที่ N เป็นค่าคงที่
เพียงตัวอย่างของสิ่งที่ฉันกำลังมองหา: ฉันสามารถแทนตัวเลขคี่ ด้วยหนึ่งบิตเช่นสำหรับช่วงตัวเลขที่กำหนด (1, 10] เริ่มต้นที่ 3:1110

พจนานุกรมต่อไปนี้สามารถบีบได้มากกว่านี้ใช่ไหม ฉันสามารถกำจัดทวีคูณของห้าด้วยงานบางอย่าง แต่ตัวเลขที่ลงท้ายด้วย 1, 3, 7 หรือ 9 ต้องอยู่ในอาร์เรย์ของบิต

ฉันจะแก้ปัญหาได้อย่างไร


3
คำขอของคุณค่อนข้างคลุมเครือ คุณให้ลายเซ็นที่ทดสอบหมายเลขเดียว แต่แล้วขอโครงสร้างข้อมูลของ (1, N]) คุณต้องการอัลกอริทึมที่สร้างพจนานุกรม <int, bool> หรือเพียงแค่ฟังก์ชั่น one-shot ที่ตรวจสอบว่าเป็นหมายเลขเดียวหรือไม่ เป็นสำคัญ?
ไมเคิลฮาเรน

@Michael ขออภัยนั่นเป็นคำอธิบายที่ดีที่สุดที่ฉันสามารถทำได้ สิ่งที่ฉันกำลังมองหาอยู่นั้นยอดเยี่ยมอย่างที่คุณพูด: พจนานุกรมบูลีน ฉันต้องการลดพื้นที่ของพจนานุกรม ขอบคุณ :)
อารักษ์

1
ถ้านั่นคือสิ่งที่คุณกำลังมองหาที่จะได้รับแล้วถาม: stackoverflow.com/questions/1032427/...
เบน S

14
คุณจะต้องถาม NSA
Charles Bretana

คำตอบ:


79

มีหลายวิธีในการทำแบบทดสอบเบื้องต้น

ไม่มีโครงสร้างข้อมูลจริงๆสำหรับคุณในการสืบค้น หากคุณมีตัวเลขจำนวนมากในการทดสอบคุณควรใช้การทดสอบความน่าจะเป็นเพราะมันจะเร็วกว่าและจากนั้นติดตามด้วยการทดสอบที่กำหนดเพื่อให้แน่ใจว่าตัวเลขนั้นดี

คุณควรรู้ว่าคณิตศาสตร์ที่อยู่เบื้องหลังอัลกอริทึมที่เร็วที่สุดนั้นไม่ได้มีไว้สำหรับคนที่ใจอ่อน


4
Miller-Rabin เป็นการทดสอบความน่าจะเป็นที่นิยมอย่างรวดเร็วในการเริ่มต้น
qwr

214

อัลกอริทึมที่เร็วที่สุดสำหรับการทดสอบที่สำคัญทั่วไปคือAKS บทความ Wikipedia อธิบายไว้ในความยาวและลิงค์ไปยังเอกสารต้นฉบับ

หากคุณต้องการที่จะหาตัวเลขใหญ่มองเข้าไปในช่วงเวลาที่มีรูปแบบพิเศษเช่นเซนเนเฉพาะ

อัลกอริทึมที่ฉันมักจะใช้ (ง่ายต่อการเข้าใจและรหัส) มีดังนี้ (ใน 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)) อัลกอริธึมทั้งหมด) ฉันจะคำนวณค่าบวกล่วงหน้า (ดูหมายเลขCarmichael ) และทำการค้นหาแบบไบนารี นี่คือการทดสอบที่เร็วที่สุดเท่าที่ฉันเคยใช้มาข้อเสียเปรียบเพียงอย่างเดียวก็คือช่วงนั้นมี จำกัด


7
สองคำถาม: คุณสามารถอธิบายสิ่งที่ตัวแปรที่ดีขึ้นiและwมีและสิ่งที่หมายโดยรูปแบบ6k-1และ6k+1? ขอบคุณสำหรับข้อมูลเชิงลึกและตัวอย่างโค้ด (ซึ่งฉันพยายามจะเข้าใจ)
Freedom_Ben

6
@Freedom_Ben คุณไปได้แล้ว, quora.com/…
Alan Dong

6
มันจะไม่ดีกว่าการคำนวณsqrtของnครั้งเดียวและเปรียบเทียบiกับมันมากกว่าการคำนวณi * iวงจรของวงทุกครั้งหรือไม่
pedros

3
@Dschoni ... แต่คุณไม่สามารถปรับใช้การทำงานที่เร็วที่สุดในช่องแสดงความคิดเห็นที่นี่เพื่อแบ่งปันกับเราได้หรือไม่
GreenAsJade

3
มันล้มเหลวสำหรับหมายเลข 1 :(
Damjan Pavlica

27

วิธีที่ดีที่สุดในความคิดของฉันคือการใช้สิ่งที่หายไปก่อน

มีรายชื่อของคนแรกที่มีNเฉพาะในอินเทอร์เน็ตกับNการยืดขึ้นไปอย่างน้อยห้าสิบล้าน ดาวน์โหลดไฟล์และใช้งานมันน่าจะเร็วกว่าวิธีอื่น ๆ ที่คุณคิด

หากคุณต้องการอัลกอริทึมที่แท้จริงสำหรับการกำหนดค่าของคุณเองวิกิพีเดียมีทุกสิ่งที่ดีสำหรับ primes ที่นี่รวมถึงลิงก์ไปยังวิธีการต่าง ๆ สำหรับการทำและการทดสอบเฉพาะที่นี่ทั้งวิธีการอิงตามความน่าจะเป็น

ควรมีความพยายามร่วมกันในการค้นหาช่วงเวลาหนึ่งพันล้านครั้ง (หรือมากกว่านั้น) และเผยแพร่พวกเขาบนอินเทอร์เน็ตในที่ใดที่หนึ่งเพื่อให้ผู้คนสามารถหยุดทำงานเดียวกันนี้ซ้ำแล้วซ้ำอีกและ ... :-)


2
@hamedbh: น่าสนใจ คุณพยายามดาวน์โหลดไฟล์เหล่านั้นหรือไม่ ดูเหมือนว่าพวกเขาไม่มีอยู่จริง
paxdiablo

ยังไม่ฉันกลัว: ฉันเพิ่งดูได้อย่างรวดเร็วในช่วงพักกลางวัน ฉันจะลบลิงค์นั้นในกรณีที่มีสิ่งใดที่เป็นอันตรายเกี่ยวกับมัน ขอโทษฉันควรตรวจสอบมันก่อน
Hamed

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

นี่เป็นเพียงการนำ c ++ ไปใช้กับอัลกอริทึม AKSด้านบน


1
มันเป็นหนึ่งในอัลกอริทึมที่กำหนดค่าได้อย่างมีประสิทธิภาพที่สุดที่ฉันเคยเจอใช่ แต่ไม่ใช่การใช้ AKS ระบบ AKS นั้นใหม่กว่าอัลกอริทึมที่สรุปไว้ มันมีประสิทธิภาพมากกว่าเนื้อหา แต่ค่อนข้างยากที่จะใช้ imo เนื่องจากค่าสัมประสิทธิ์ factorials / binomial ที่มีขนาดใหญ่
CogitoErgoCogitoSum

สิ่งนี้แตกต่างจากคำตอบที่ Derri Leahi (ไม่ใช่ -) (นอกเหนือจาก C แทนที่จะเป็น Java) อย่างไร คำตอบนี้เป็นWhat is the algorithm that produces a data structure with lowest memory consumption for the range (1, N]อย่างไร
greybeard

1
(n% i == 0 || n% (i + 2) == 0) สอดคล้องกับ 6n + 1 & 6n-1 อย่างไร
yesh

@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 *
greybeard

นอกจากนี้ทราบว่าขั้นตอนวิธีนี้ไม่ได้ให้ผลที่ถูกต้องสำหรับการและ5 7
Athan Clark

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. คำตอบนี้ใช้ห่วงบางขณะ:

    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

ตามวิกิพีเดียตะแกรงของ Eratosthenesมีความซับซ้อนO(n * (log n) * (log log n))และต้องการO(n)หน่วยความจำ - ดังนั้นจึงเป็นจุดเริ่มต้นที่ดีถ้าคุณไม่ได้ทดสอบจำนวนมากเป็นพิเศษ


ขออภัยฉันรู้ว่าคำอธิบายของฉันคลุมเครือฉันไม่ได้ดู SOE :) ดูความคิดเห็นของฉัน
@Michael

6

หนึ่งสามารถใช้ SymPy

import sympy

sympy.ntheory.primetest.isprime(33393939393929292929292911111111)

True

จากเอกสาร sympy ขั้นตอนแรกคือการมองหาปัจจัยเล็ก ๆ น้อย ๆ ซึ่งหากพบจะทำให้ได้ผลตอบแทนที่รวดเร็ว ถัดไปถ้าตะแกรงมีขนาดใหญ่พอให้ใช้การค้นหาแบบแยกส่วนบนตะแกรง สำหรับตัวเลขขนาดเล็กชุดทดสอบ Miller-Rabin แบบกำหนดรูปแบบจะดำเนินการกับฐานที่ทราบกันดีว่าไม่มีตัวอย่างตอบโต้ในช่วงของพวกเขา ในที่สุดหากจำนวนมากกว่า 2 ^ 64 การทดสอบ BPSW ที่แข็งแกร่งจะดำเนินการ ในขณะที่นี่คือการทดสอบที่น่าจะเป็นไปได้ที่สำคัญและเราเชื่อว่ามีตัวอย่างคู่อยู่จริง แต่ไม่มีตัวอย่างที่เป็นที่รู้จัก


อัลกอริทึมเป็นลำดับขั้นตอนที่กำหนดไว้อย่างดีซึ่งกำหนดวิธีแก้ปัญหาแบบนามธรรมให้กับปัญหา - ลำดับขั้นตอนที่เป็นไปได้ของโค้ดที่นำเสนอคืออะไร มันคือmemory consumptionอะไร
greybeard

2
@greybeard จากเอกสาร sympy ขั้นตอนแรกคือการมองหาปัจจัยเล็ก ๆ น้อย ๆ ซึ่งหากพบจะทำให้ได้ผลตอบแทนที่รวดเร็ว ถัดไปถ้าตะแกรงมีขนาดใหญ่พอให้ใช้การค้นหาแบบแยกส่วนบนตะแกรง สำหรับตัวเลขขนาดเล็กชุดทดสอบ Miller-Rabin แบบกำหนดรูปแบบจะดำเนินการกับฐานที่ทราบกันดีว่าไม่มีตัวอย่างตอบโต้ในช่วงของพวกเขา ในที่สุดหากจำนวนมากกว่า 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) ถ้า <2:ถ้า "a" น้อยกว่า 2 จะไม่ถือว่าเป็นเรื่องสำคัญ

2) elif a! = 2 และ a% 2 == 0:ถ้า "a" หารด้วย 2 ก็จะไม่เป็นนายก แต่ถ้า = 2 เราไม่ต้องการประเมินมันเพราะมันเป็นจำนวนเฉพาะ ดังนั้นเงื่อนไข a! = 2

3) ส่งคืนทั้งหมด (a% i สำหรับ i ในช่วง (3, int (a 0.5) +1)): ** ดูที่คำสั่ง all () ทั้งหมดใน python เริ่มจาก 3 เราหาร "a" จนถึงรากที่สอง (a ** 0.5) ถ้า "a" หารลงตัวผลลัพธ์จะเป็นเท็จ ทำไมต้องสแควร์รูท? สมมุติว่า a = 16 สแควร์รูทของ 16 = 4 เราไม่จำเป็นต้องประเมินจนถึง 15 เราแค่ต้องตรวจสอบจนถึง 4 เพื่อบอกว่ามันไม่ได้เป็นนายก

พิเศษ: การวนซ้ำสำหรับการค้นหาหมายเลขเฉพาะทั้งหมดภายในช่วง

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

1
สิ่งนี้แตกต่างจากคำตอบของ Oleksandr Shmyheliukอย่างไร (ทั้งคู่พลาด "ขั้นตอนที่ 2" ในrange()... )
greybeard

1
หากตัวเลขเป็นเลขคู่จะไม่ใช่ค่าเฉพาะ (ยกเว้น 2) ดังนั้นไม่จำเป็นต้องตรวจสอบตัวเลขแม้กระทั่ง นี่จะเร็วขึ้นมากถ้าคุณต้องการรับจำนวนเฉพาะภายในช่วง มันจะตรงขึ้นไม่รวมถึงเลขคู่
Growal ลึก


3

สำหรับจำนวนมากคุณไม่สามารถตรวจสอบได้อย่างไร้เดียงสาว่าหมายเลขผู้สมัครที่หารด้วยจำนวนที่น้อยกว่า sqrt (N) หรือไม่ มีการทดสอบที่ปรับขนาดได้อีกมากมายเช่นการทดสอบเบื้องต้นของMiller-Rabin ด้านล่างคุณมีการนำไปใช้ในหลาม:

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!

หากคุณกำลังทดสอบจำนวนเต็มแบบสุ่มคุณอาจต้องการทดสอบก่อนว่าจำนวนผู้สมัครใด ๆ หารด้วยจำนวนเฉพาะที่น้อยกว่า 1,000 คำพูดก่อนที่คุณจะเรียก Miller-Rabin ซึ่งจะช่วยคุณกรองช่วงเวลาที่ชัดเจนเช่น 10444344345


นี่คือการทดสอบมิลเลอร์ การทดสอบ Miller-Rabin เป็นเวอร์ชั่นที่น่าจะเป็นซึ่งฐานทดสอบแบบสุ่มจะถูกทดสอบจนกว่าจะมีความมั่นใจเพียงพอ นอกจากนี้การทดสอบมิลเลอร์ไม่ได้ขึ้นอยู่กับสมมติฐานของรีมันน์โดยตรง แต่สมมติฐานทั่วไปของรีมันน์ (GRH) สำหรับอักขระ Diriclet กำลังสอง (ฉันรู้ว่ามันเป็นคำหนึ่งและฉันก็ไม่เข้าใจเหมือนกัน) ซึ่งหมายความว่าข้อพิสูจน์ที่เป็นไปได้สำหรับสมมติฐานของ Riemann อาจไม่ได้นำไปใช้กับ GRH และด้วยเหตุนี้จึงไม่ได้พิสูจน์การทดสอบ Miller ให้ถูกต้อง กรณีที่เลวร้ายยิ่งกว่านั้นคือแน่นอนหาก GRH ไม่ได้รับการพิสูจน์
Arne Vogel

2

สายไปงานเลี้ยงสายเกินไป แต่หวังว่าสิ่งนี้จะช่วยได้ สิ่งนี้เกี่ยวข้องถ้าคุณกำลังมองหาสิ่งสำคัญ:

ในการทดสอบตัวเลขคี่ขนาดใหญ่คุณจำเป็นต้องใช้การทดสอบแบบแฟร์มาต์และ / หรือการทดสอบแบบมิลเลอร์ - ราบิน

การทดสอบเหล่านี้ใช้การยกกำลังแบบแยกส่วนซึ่งค่อนข้างแพงสำหรับการnยกกำลังแบบบิตที่คุณต้องการอย่างน้อยการnคูณnint ใหญ่และการหารint ขนาดใหญ่ ซึ่งหมายถึงความซับซ้อนของการยกกำลังแบบแยกส่วนคือ O (n³)

ดังนั้นก่อนที่จะใช้ปืนใหญ่คุณต้องทำการทดลองหลายครั้ง แต่อย่าทำอย่างไร้เดียงสามีวิธีทำให้เร็ว ก่อนอื่นคูณจำนวนเฉพาะเข้าด้วยกันให้มากที่สุดเท่ากับคำที่คุณใช้สำหรับจำนวนเต็มขนาดใหญ่ หากคุณใช้คำ 32 บิตคูณ 3 * 5 * 7 * 11 * 13 * 17 * 19 * 23 * 29 = 3234846615 และคำนวณตัวหารร่วมมากที่สุดด้วยหมายเลขที่คุณทดสอบโดยใช้อัลกอริทึมแบบยุคลิด หลังจากขั้นตอนแรกตัวเลขจะลดลงต่ำกว่าขนาดคำและดำเนินการตามขั้นตอนต่อไปโดยไม่ต้องทำการหารจำนวนเต็มสมบูรณ์ ถ้า GCD! = 1 นั่นหมายถึงหนึ่งในช่วงเวลาที่คุณคูณด้วยกันหารจำนวนดังนั้นคุณจึงมีหลักฐานไม่สำคัญ จากนั้นดำเนินการกับ 31 * 37 * 41 * 43 * 47 = 95041567 และอื่น ๆ

เมื่อคุณทดสอบหลายร้อยครั้ง (หรือพันครั้ง) ด้วยวิธีนี้คุณสามารถทำการทดสอบ Miller-Rabin 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 / x

สุดท้ายrange(2, int(sqrt(num)))หมายความว่ามันจะสร้างรายการที่เริ่มต้นที่ 2 และสิ้นสุดที่int(sqrt(num)+1)

สำหรับข้อมูลเพิ่มเติมเกี่ยวกับช่วงดูที่เว็บไซต์นี้ !

num > 1ส่วนหนึ่งเป็นเพียงการตรวจสอบหากตัวแปรnumที่มีขนาดใหญ่กว่า 1, เพราะที่ 1 และ 0 ไม่ถือว่าเป็นตัวเลขที่สำคัญ

ฉันหวังว่านี่จะช่วยได้ :)


โปรดยืนยันว่านี่เป็นthe bestอัลกอริทึมหรือดีอย่างไร
greybeard

@greybeard, ฟังก์ชั่นที่ดีที่สุดส่วนใหญ่ที่นี่ไม่ไปถึง (2 ^ 31) -1 หรือใช้เวลานานเกินไปสำหรับตัวเลขที่สูง แต่การทำงานของฉันจนถึง (2 ^ 61) -1 ดังนั้นคุณสามารถตรวจสอบว่าตัวเลขนั้นมีความกว้างกว่าหรือไม่ ช่วงของตัวเลข
WhyAreYouReadingThis

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จะออกจาก
aneroid

1

อัลกอริธึมที่ดีที่สุดสำหรับ javascript number ของ 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³อื่น ๆ พูดว่าอะไร?
greybeard

1

ฉันขอแนะนำให้คุณแก้ปัญหาที่สมบูรณ์แบบสำหรับจำนวนเต็ม 64 บิต ขออภัยที่ใช้ C # คุณยังไม่ได้ระบุว่าเป็นงูใหญ่ในโพสต์แรกของคุณ ฉันหวังว่าคุณจะสามารถหาฟังก์ชั่น 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
มันจะดีกว่าถ้าคุณเพิ่มคำอธิบายบางอย่างเพื่อให้คำตอบของคุณโดยใช้แก้ไข อาจไม่ชัดเจนสำหรับผู้อ่านหลายคนว่าทำไมคำตอบของคุณจึงเป็นคำตอบที่ดีและพวกเขาสามารถเรียนรู้จากคุณได้หากคุณอธิบายเพิ่มเติม
Brian Tompsett - 汤莱恩

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
greybeard

ในการวนรอบคุณไม่จำเป็นต้องตรวจสอบ "i <= จำกัด " ก็พอที่จะ ckeck "i <จำกัด " ดังนั้นในการวนซ้ำทุกครั้งคุณจะทำการเปรียบเทียบน้อยลง
Andrushenko Alexander

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
เมื่อคุณเขียนคำตอบแม้ว่าจะถูกต้องแล้วโปรดเขียนอธิบายสิ่งที่คุณกำลังทำอยู่และทำไม วิธีนี้ทำให้ผู้คนที่อ่านคำตอบของคุณสามารถเข้าใจสิ่งที่คุณแก้ไขได้ง่ายขึ้น ขอบคุณ!
kim

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 และฉันรู้ว่ามันไม่สมบูรณ์แบบขอบคุณสำหรับการแสดงความคิดเห็นต่อไป
Patrick Jane

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

เราสามารถใช้กระแสข้อมูลจาวาเพื่อใช้สิ่งนี้ใน 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 สตรีมและ lambdas มันสามารถนำไปใช้ได้เช่นนี้ในไม่กี่บรรทัด:

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" เพื่อรวม candidateRoot ควรจัดการกับผู้สมัคร <2 รายด้วย
udalmik

สิ่งนี้แตกต่างจากคำตอบก่อนหน้าของ alirezafnaticaอย่างไร
greybeard

0

นี่คือคำตอบของฉัน:

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

ฟังก์ชั่นจะคืนค่าจริงถ้าคุณสมบัติด้านล่างใด ๆ เป็นจริง คุณสมบัติเหล่านั้นในทางคณิตศาสตร์กำหนดสิ่งที่สำคัญคือ

  1. จำนวนน้อยกว่าหรือเท่ากับ 3
  2. ตัวเลข + 1 หารด้วย 6
  3. จำนวน - 1 หารด้วย 6

>>> isprime(25)Trueผลตอบแทน คุณกำลังตรวจสอบที่ง่ายมากที่จำเป็นสภาพ (หาร 2 หรือ 3) แต่นี้ไม่เพียงพอ
DanaJ

Nice คุณกำลังจับคู่โดยคุณสมบัตินี้: ทุกหมายเลขเฉพาะที่มากกว่า 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==1n=1
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.