N sınırına kadar en kompakt eşleme n → isprime (n) nasıl oluşturulur?


152

Doğal olarak, bool isprime(number)sorgulayabileceğim bir veri yapısı olurdu.
Ben iyi algoritma tanımlamak N bir sabittir aralık (1, N], için en düşük bellek tüketimi ile bir veri yapısını üreten algoritma olması.
Ben ne arıyorum Sadece bir örnek: Her tek sayı temsil edebilir bir bitle, örneğin verilen sayı aralığı için (1, 10], 3'te başlar:1110

Aşağıdaki sözlük daha fazla sıkıştırılabilir, değil mi? Bazı çalışmalarla beşin katlarını ortadan kaldırabilirim, ancak bit dizisinde 1, 3, 7 veya 9 ile biten sayılar olmalı.

Sorunu nasıl çözebilirim?


3
Talebiniz biraz belirsiz. Tek bir sayıyı sınayan bir imza verirsiniz ve daha sonra (1, N] veri yapısını istersiniz. sözlük <int, bool> veya yalnızca tek bir sayı olup olmadığını kontrol eden tek çekim işlevi üreten bir algoritma ister misiniz? asal?
Michael Haren

@Michael Üzgünüm, gelebileceğim en iyi açıklama bu. Ne arıyorum tam olarak söylediğin gibi: bir boolean sözlük. Sözlüğün alanını en aza indirmek istiyorum. Teşekkürler :)
AraK

1
Eğer aradığınız bu ise zaten sorulmuştur: stackoverflow.com/questions/1032427/…
Ben S


Yanıtlar:


79

Öncelik testini yapmanın birçok yolu vardır .

Sorgulayacağınız bir veri yapısı yoktur. Test edilecek çok sayıda numaranız varsa, muhtemelen daha hızlı olduğundan olasılıklı bir test yapmalı ve daha sonra sayının asal olduğundan emin olmak için bir deterministik testle takip etmelisiniz .

En hızlı algoritmaların ardındaki matematiğin kalbin zayıflığı için olmadığını bilmelisiniz.


4
Miller-Rabin, başlamak için popüler bir hızlı olasılık testidir.
qwr

214

Genel prime testi için en hızlı algoritma AKS'dir . Wikipedia makalesi, uzunluğu ve orijinal makaleye bağlantılarla açıklamaktadır.

Büyük sayılar bulmak istiyorsanız, Mersenne asalları gibi özel formları olan asallara bakın .

Genellikle uyguladığım algoritma (anlaşılması ve kodlanması kolaydır) aşağıdaki gibidir (Python'da):

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

Klasik O(sqrt(N))algoritmanın bir varyantı . Bir asalın (2 ve 3 hariç) formda olduğu 6k - 1ya da 6k + 1sadece bu formun bölenlerine baktığı gerçeğini kullanır .

Bazen, gerçekten hız istiyor ve menzil sınırlıysa , Fermat'ın küçük teoremine dayanan bir sahte prime testi uygularım . Gerçekten daha fazla hız istiyorsam (yani O (sqrt (N)) algoritmasından tamamen kaçının), yanlış pozitifleri önceden hesaplar (bkz. Carmichael sayıları) ve ikili bir arama yaparım. Bu şimdiye kadar uyguladığım en hızlı test, tek dezavantajı aralığın sınırlı olmasıdır.


7
İki soru: daha iyi değişkenleri neyi açıklayabilir ive wvardır ve hangi formda kastedildiğini 6k-1ve 6k+1? Fikriniz ve (anlamaya çalıştığım) kod örneği için teşekkür ederiz
Freedom_Ben

6
@Freedom_Ben Buyrun, quora.com/…
Alan Dong

6
O hesaplamak daha iyi olmaz sqrtait nbir kez ve karşılaştırma ibuna ziyade hesaplama i * idöngünün her döngü?
pedros

3
@Dschoni ... ancak bizimle paylaşmak için buradaki yorum alanlarındaki en hızlı uygulamaya sığamaz mısınız?
GreenAsJade

3
1 numara için başarısız oluyor :(
Damjan Pavlica

27

En iyi yöntem, bence, daha önce olanları kullanmaktır.

Nİnternette Nen az elli milyona kadar uzanan ilk asalların listeleri var . Dosyaları indirin ve kullanın, geleceğiniz diğer yöntemlerden çok daha hızlı olması muhtemeldir.

Kendi primerlerinizi yapmak için gerçek bir algoritma istiyorsanız, Wikipedia, burada yapmak için çeşitli yöntemlere bağlantılar ve burada hem olasılık tabanlı hem de hızlı belirleyici yöntemler içeren birincil testler de dahil olmak üzere , primerlerde her türlü iyi malzemeye sahiptir .

İlk milyar (veya daha fazla) primeri bulmak ve bir yerde internette yayınlamak için ortak bir çaba olmalı, böylece insanlar aynı işi tekrar tekrar durdurabilir ve ... :-)


2
@hamedbh: İlginç. Bu dosyaları indirmeyi denediniz mi? Görünüşe göre onlar yok.
paxdiablo

Henüz değil, korkuyorum: Öğle tatilim sırasında çabucak bakıyordum. Kötü niyetli bir şey olması durumunda bu bağlantıyı sileceğim. Çok üzgünüm, önce kontrol etmeliydim.
Hamed

1
Bu listeler yapmak vardır. Onları yıllar önce gördüm ama onları indirmek için hiç umursamadım. Gerçek şu ki, çok fazla yer kaplarlar (nispeten konuşurlar) ve birinin sattığı veya dağıttığı programlara dahil edilmemelidirler. Dahası, her zaman ve sonsuza dek eksik olacaklar. Bir program kullanımı sırasında pratikte ortaya çıkan her sayıyı test etmek daha mantıklıdır, çünkü sahip olabileceğiniz herhangi bir listenin uzunluğundan daha az test edilecektir. Ayrıca, pax'ın birincil algoritmaların amacını gerçekleştirmediğini düşünüyorum, çoğu zaman, aslında primer bulmaktan ziyade verimliliği / hızı test etmektir.
CogitoErgoCogitoSum

2
@CogitoErgoCogitoSum, sayısız sonsuz olduklarını gösteren matematiksel kanıtları gördüğümden beri tüm asal listelerin sonsuza kadar çıkacağını kabul edin. Ancak, ilk xprimler listesi inşa
edildikten

1
Doğru, ancak bir dosyadan doğrusal bir şekilde okumaktan daha iyi depolama yöntemleri vardır. Eğer varsa gerçekten önceden oluşturulmuş asal bir saklı kümesinden okumak istiyorum, daha karmaşık veri yapısını denemek böyle bir sorun yukarı hızları.
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;
}

Bu sadece yukarıdaki AKS algoritmasının c ++ uygulamasıdır


1
Karşılaştığım en etkili deterministik algoritmalardan biri, evet, ama AKS'nin bir uygulaması değil. AKS sistemi, özetlenen algoritmadan çok daha yenidir. Tartışmasız daha verimlidir, ancak potansiyel olarak astronomik olarak büyük faktöriyeller / binom katsayıları nedeniyle imo'nun uygulanması biraz zordur.
CogitoErgoCogitoSum

Bu Derri Leahi'nin (olmayan) cevabından nasıl farklıdır (Java yerine C dışında)? Bu nasıl cevap veriyor 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'e nasıl karşılık gelir?
yesh

@YeshwanthVenkatesh: How does (n%i == 0 || n%(i+2) == 0) correspond to 6n+1 & 6n-1?cevabın bir kısmı farklı roller n, diğeri (6n-1) +0 & (6n-1) + 2 * 'ye eşdeğer 6n + 1 & 6n-1 .
greybeard

Ayrıca bu algoritmanın 5ve için doğru sonucu vermediğini unutmayın 7.
Athan Clark

7

Bir sayının asal olup olmadığını belirlemek için en popüler önerilerin verimliliğini karşılaştırdım. Kullandığım python 3.6üzerinde ubuntu 17.10; 100.000'e kadar sayılarla test ettim (aşağıdaki kodumu kullanarak daha büyük sayılarla test edebilirsiniz).

Bu ilk grafik, (cevabımda daha sonra açıklanacak olan) fonksiyonları karşılaştırır ve son fonksiyonların sayıları arttırırken ilk fonksiyon kadar hızlı büyümediğini gösterir.

plot1

İkinci grafikte, asal sayılar durumunda zamanın sabit bir şekilde büyüdüğünü görebiliriz, ancak asal olmayan sayılar zamanla çok hızlı büyümez (çünkü çoğu erken ortadan kaldırılabilir).

plot2

İşte kullandığım fonksiyonlar:

  1. bu cevap ve bu cevapall() şunları kullanarak bir yapı önerdi :

    def is_prime_1(n):
        return n > 1 and all(n % i for i in range(2, int(math.sqrt(n)) + 1))
    
  2. Bu cevap bir çeşit while döngüsü kullandı:

    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. Bu cevap , fordöngülü bir sürümü içeriyordu :

    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. Ve diğer cevaplardan birkaç fikri yenisine karıştırdım:

    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
    

Varyantları karşılaştırmak için benim komut dosyası:

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

İşlevi compare_functions(n=10**5)(100.000'e kadar olan sayılar) çalıştırarak bu çıktıyı alıyorum:

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

Sonra, fonksiyonu compare_functions(n=10**6)(1.000.000'a kadar sayılar) çalıştırarak bu çıktıyı alıyorum:

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

Sonuçları çizmek için aşağıdaki komut dosyasını kullandım:

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

Birisi sempozyum kullanabilir .

import sympy

sympy.ntheory.primetest.isprime(33393939393929292929292911111111)

True

Sympy docs'dan. İlk adım, bulunursa hızlı bir geri dönüş sağlayan önemsiz faktörleri aramaktır. Daha sonra, elek yeterince büyükse, elek üzerinde bölmeli arama kullanın. Küçük sayılar için, aralarında herhangi bir karşı örnek olmadığı bilinen bazlarla bir dizi deterministik Miller-Rabin testi yapılır. Son olarak, sayı 2 ^ 64'den büyükse, güçlü bir BPSW testi gerçekleştirilir. Bu olası bir asal test olmakla birlikte, karşı örneklerin var olduğuna inanıyoruz, bilinen karşı örnek yok


Algoritma, bir soruna soyut bir çözüm tanımlayan iyi tanımlanmış adımlar dizisidir. - sunulan kodda akla gelebilecek adımlar sırası nedir? Nedir bu memory consumption?
greybeard

2
@greybeard. Sympy docs'dan. İlk adım, bulunursa hızlı bir geri dönüş sağlayan önemsiz faktörleri aramaktır. Daha sonra, elek yeterince büyükse, elek üzerinde bölmeli arama kullanın. Küçük sayılar için, aralarında herhangi bir karşı örnek olmadığı bilinen bazlarla bir dizi deterministik Miller-Rabin testi yapılır. Son olarak, sayı 2 ^ 64'den büyükse, güçlü bir BPSW testi gerçekleştirilir. Bu olası bir asal test olmakla birlikte, karşı örneklerin var olduğuna inanıyoruz, ancak bilinen karşı örnek yoktur.
LetzerWille

6

Python 3'te:

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

Açıklama: Asal sayı yalnızca kendi başına bölünebilen bir sayıdır ve Örn: 2,3,5,7 ...

1) eğer <2 ise: "a" 2'den küçükse asal değildir.

2) elif a! = 2 ve% 2 == 0: "a" 2 ile bölünebiliyorsa, bu kesinlikle bir asal değildir. Ama eğer a = 2 ise asal sayı olduğu için bunu değerlendirmek istemiyoruz. Dolayısıyla a! = 2 koşulu

3) tümünü döndür (i aralığında (3, int ( 0,5) +1) i için% i )): ** İlk önce python'da all () komutunun ne yaptığına bakın. 3'ten başlayarak "a" yı kareköküne (a ** 0.5) böleriz. "A" bölünebilirse, çıktı Yanlış olacaktır. Neden karekök? Diyelim ki a = 16. 16 = 4'ün karekökü. 15'e kadar değerlendirmemiz gerekmiyor. Sadece 4'e kadar kontrol etmeliyiz.

Ekstra: Bir aralıktaki tüm asal sayıları bulmak için bir döngü.

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

1
Bunun Oleksandr Shmyheliuk'un cevabından farkı nedir? (Her ikisi de bir "adım 2" özledim range()...)
greybeard

1
Bir sayı çift bile olsa, asal değildir (2 hariç). Yani çift sayıları kontrol etmeye gerek yok. Bir aralıkta asal sayı almak istiyorsanız bu çok daha hızlı olacaktır. Düzgün çift sayıları hariç tutar.
derin büyü


3

Büyük sayılar için, N numarası adayının sqrt (N) 'den küçük sayılardan hiçbirine bölünemez olup olmadığını naif olarak kontrol edemezsiniz. Miller-Rabin öncelik testi gibi çok daha ölçeklenebilir testler mevcuttur . Aşağıda python uygulamasına sahipsiniz:

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üyük asal sayılar bulmak için kullanabilirsiniz:

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

# 10000000000000000000000000000000000000000000000000000000000000000000000000133 is a prime!

Rastgele tam sayıları test ediyorsanız, muhtemelen aday numarasının Miller-Rabin'i aramadan önce 1000'den daha küçük olan primerlerden herhangi birine bölünebilir olup olmadığını test etmek istersiniz. Bu, 10444344345 gibi belirgin primer olmayanları filtrelemenize yardımcı olacaktır.


Bu Miller testi. Miller-Rabin testi, rastgele seçilen bazların yeterli güven elde edilene kadar test edildiği olasılıklı versiyondur. Ayrıca, Miller testi doğrudan Riemann Hipotezine değil, kuadratik Diriclet karakterleri için Genelleştirilmiş Riemann Hipotezine (GRH) bağlıdır (bunun bir ağız dolusu olduğunu biliyorum ve ben de anlamıyorum). Bu, Riemann Hipotezi için potansiyel bir kanıtın GRH için geçerli olmayabileceği ve bu nedenle Miller testinin doğru olduğunu kanıtlayamayacağı anlamına gelir. GRH onaylanmadığı takdirde daha da kötü bir durum söz konusudur.
Arne Vogel

2

Partiye çok geç, ama umarım bu yardımcı olur. Büyük asallar arıyorsanız, bu önemlidir:

Büyük tek sayıları test etmek için Fermat testi ve / veya Miller-Rabin testini kullanmanız gerekir.

Bu testler oldukça pahalı olan modüler üs alma kullanır, nbit üs alma için en azından nbüyük int çarpma ve nbüyük int bölme gerekir. Bu, modüler üslemenin karmaşıklığının O (n³) olduğu anlamına gelir.

Bu yüzden büyük silahları kullanmadan önce birkaç deneme bölümü yapmanız gerekiyor. Ama safça yapma, onları hızlı yapmanın bir yolu var. Öncelikle, büyük tamsayılar için kullandığınız kelimelere sığabilecek kadar çok asal sayıları çarpın. 32 bit sözcükler kullanıyorsanız, 3 * 5 * 7 * 11 * 13 * 17 * 19 * 23 * 29 = 3234846615 ile Öklid algoritmasını kullanarak test ettiğiniz sayı ile en büyük böleni hesaplayın. İlk adımdan sonra sayı, kelime boyutunun altına küçültülür ve tam büyük tamsayı bölümleri gerçekleştirmeden algoritmaya devam edilir. GCD! = 1 ise, bu, birlikte çarptığınız asal sayılardan birinin sayıyı böldüğü anlamına gelir, bu nedenle asal olmadığını kanıtlayın. Ardından 31 * 37 * 41 * 43 * 47 = 95041567 vb. İle devam edin.

Birkaç yüz (veya bin) primeri bu şekilde test ettikten sonra, sayının asal olduğunu doğrulamak için 40 mermi Miller-Rabin testi yapabilirsiniz, 40 mermiden sonra numaranın sadece 2 ^ -80 şansı olduğundan emin olabilirsiniz değil (muhtemelen donanım arızalarınız ...).


1

(2 ^ 61) -1 kadar çalışan bir asal fonksiyon var Burada:

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

Açıklama:

all()Fonksiyon buna yeniden tanımlanabilir:

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

all()Fonksiyon sadece bool değerlerden oluşan / numaraları ve getiri bir dizi geçer FalseDurum 0 veya görürse False.

sqrt()Fonksiyonu sadece yapıyor karekökünü Sayının.

Örneğin:

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

num % xParçası döner kalan num / x.

Son olarak, 2'de başlayan ve şu saatte biten range(2, int(sqrt(num)))bir liste oluşturacağı anlamına gelir :int(sqrt(num)+1)

Menzil hakkında daha fazla bilgi için bu web sitesine bir göz atın !

num > 1Değişken eğer parçası sadece kontrol edilir num1 ve 0 asal sayılar dikkate alınmaz çünkü, daha büyük 1'dir.

Umarım bu yardımcı olmuştur :)


Lütfen bunun the bestalgoritma, hatta iyi bir algoritma olduğunu tartışın .
greybeard

@greybeard, Buradaki çoğu asal işlev (2 ^ 31) -1'e kadar gitmez veya yüksek sayılar için çok uzun sürer, ancak benimki (2 ^ 61) -1'e kadar çalışır, böylece bir sayının daha geniş olanla asal olup olmadığını kontrol edebilirsiniz sayı aralığı.
Neden?

1

Python'da:

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

Matematiksel formalizmden Python'a daha doğrudan bir dönüşüm, tümünü (n% p! = 0 ...) kullanır , ancak bu, p'nin tüm değerlerinin sıkı bir şekilde değerlendirilmesini gerektirir. Herhangi bir gerçek değer bulunursa versiyonu erken kesebilirler.


Wrt "all (n% p! = 0 ...), ancak bu p'nin tüm değerlerinin katı bir şekilde değerlendirilmesini gerektirir" - bu yanlıştır. anyve allikisi de erken çıkacak . İlk başta Yani pnerede n % polduğunu 0, allçıkmak istiyorum.
aneroid

1

asal sayı javascript için en iyi algoritma

 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

Asal sayı, yalnızca 1 ve kendisi tarafından bölünebilen herhangi bir sayıdır. Diğer tüm numaralara bileşik denir .

Asal bir sayı bulmanın en basit yolu, giriş numarasının bileşik bir sayı olup olmadığını kontrol etmektir:

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

Programın değerini number tüm sayıların 1'den . Bu sayı sadece tek bir kişiye eşit olarak bölünemezse, bileşik bir sayıdır.

Değişkenin başlangıç ​​değeri i2 olmalıdır, çünkü hem asal hem de bileşik sayılar eşit olarak 1'e bölünebilir.

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

O zaman idaha aznumber aynı nedenden . Hem asal hem de kompozit sayılar eşit olarak bölünebilir. Bu nedenle kontrol etmek için bir neden yoktur.

Ardından, kalan operatörü kullanarak değişkenin eşit olarak bölünüp bölünemeyeceğini kontrol ederiz.

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

Kalan sıfır ise, number , bu eşit olarak bölünebilir, dolayısıyla bileşik bir sayı ve yanlış döndürür.

Girilen sayı koşulu karşılamıyorsa, bunun bir asal sayı olduğu ve işlev true olarak döndüğü anlamına gelir.


1
(En iyisimplest geçerli bir yorum olduğunu düşünürken :) Soru, bir sayının asal olup olmadığını kontrol etmek için en iyi algoritma nedir? : Bölünebilirliği kontrol etmek avantajlı mı? Ne olmuş ? Diğer 3³ cevaplarının anlaşılır cevapları ne diyor? number / 2 < i < numbernumber < i*i
greybeard

1

Size 64 bit tamsayılar için mükemmel çözümü önereyim. C # kullandığım için üzgünüm. İlk yayınınızda zaten python olarak belirtmediniz. Umarım basit bir modPow işlevi bulabilir ve kolayca analiz edebilirsiniz.

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

herhangi bir sayı için, sayının asal olup olmadığını kontrol etmek için minimum tekrarlar sayının 2 ila karekökü olabilir. Yinelemeleri daha da azaltmak için, sayının 2 veya 3 ile bölünebilir olup olmadığını kontrol edebiliriz, çünkü sayının 2 veya 3 ile bölünebilir olup olmadığını kontrol ederek maksimum sayılar ortadan kaldırılabilir. +1 veya 6k-1. Böylece yineleme 6k + 1'den sayının kare köküne kadar gidebilir.


1
Eğer kullanarak cevap için biraz açıklama eklendi eğer daha iyi olurdu düzenlemek . Cevabınızın neden iyi bir cevap olduğu pek çok okuyucuya açık olmayabilir ve daha fazla açıklarsanız sizden öğrenebilirler.
Brian Tompsett - 汤 莱恩

0

En küçük bellek? Bu en küçük değil, doğru yönde atılmış bir adım.

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

Tabii ki, tanımını belirtmelisiniz CheckPrimality.


0

En hızlı yöntemlerden biri benim yaptığım yöntem.

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
bir hata olabilir ... 6 - i?
Hmmm

0

Bahsedilen AKS algoritmasına benzer fikir

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 algoritması ile ilişkisi yok .
greybeard

For döngüsünde "i <= limit" i işaretlemenize gerek yoktur, "i <limit" işaretlemeniz yeterlidir. Yani her yinelemede bir karşılaştırmayı daha az yaparsınız.
Andrushenko Alexander

0

Bir aralıktaki sayı veya sayıların asal olup olmadığını bulmak için.

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

Bu kodu çalıştırın hem liste hem de belirli bir sayı için çalışacaktır
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
Bir cevap yazdığınızda, doğru olsa bile, lütfen ne yaptığınızı ve nedenini açıklayan bir parça da yazın. Bu şekilde cevabınızı okuyan insanlar çözdüklerinizi daha kolay kavrayabilirler. Teşekkür ederim!
kim

1
Tabii Kim, bunu belirttiğin için teşekkür ederim.
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öyle bir şey deneyebilirsiniz.

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

Bu, öncelikliliği test etmek için korkunç bir çözümdür. Bir kere bir böleni, cevabı biliyorum, ama bu kod bulur tüm bölenler ve sonra karar verir! Ve OP'nin her zaman geri döndüğü için bir boole yüklemi talebini göz ardı eder None.
cdlane

@cdlane biliyorum bu isol boolean dönüş fonksiyonu, ben hala python bir acemi ve yine de mükemmel olmadığını biliyorum, yine de yorum için teşekkürler
Patrick Jane

0

Önceki cevapların çoğu doğrudur, ancak bir sayının asal sayı olduğunu test etmenin bir yolu daha vardır. Tazeleme olarak, asal sayılar , tek faktörleri 1 ve kendisi olan 1'den büyük tam sayıdır. ( Kaynak )

Çözüm:

Genellikle bir döngü oluşturabilir ve test ettiğiniz sayıya kadar 1,2,3 ... 'e bölünebilir olup olmadığını görmek için numaranızı test etmeye başlayabilirsiniz ... vb. Ancak kontrol süresini kısaltmak için numaranızı bir sayının değerinin yarısından fazlası ile tam olarak bölünemeyeceği için, sayınızın değerinin yarısı kadar. Örneğin, 100'ün 50'ye kadar döngü yapabileceği asal bir sayı olduğunu görmek istiyorsanız.

Gerçek kod :

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

Sadece sayının yarısından biraz daha küçük olan sayının kare kökünü kontrol etmeniz gerekir. Örneğin n = 100 için 50'ye değil, sadece 10'a bakmanız gerekir. Neden? Tam olarak karekökte, iki faktör eşittir. Diğer herhangi bir faktör için biri sqrt (n) 'den küçük ve diğeri daha büyük olacaktır. Bu nedenle, sqrt (n) 'ye kadar olan kontrolleri yaptığımızda bir tane görmediysek, sonra bir tane bulamayacağız.
DanaJ

0

Java akışlarını O (sqrt (n)) dilinde uygulamak için kullanabiliriz; NoneMatch öğesinin, sonucu belirlemek için gereksiz bulduğunda işlemi durduran bir shortCircuiting yöntemi olduğunu düşünün:

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 akışları ve lambdasların yardımıyla, sadece birkaç satırda bu şekilde uygulanabilir:

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

Performans O (sqrt (N)) değerine yakın olmalıdır . Belki birisi bunu yararlı bulur.


candidateRoot'u dahil etmek için "range", "rangeClosed" ile değiştirilmelidir. Ayrıca aday <2 vaka ele alınmalıdır.
udalmik


0

İşte cevabı almam:

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

Aşağıdaki özelliklerden herhangi biri True ise işlev True değerini döndürür. Bu özellikler bir asalın ne olduğunu matematiksel olarak tanımlar.

  1. Sayı 3'e eşit veya 3'e eşit
  2. + 1 sayısı 6'ya bölünebilir
  3. - 1 sayısı 6'ya bölünebilir

>>> isprime(25)döner True. Çok basit bir gerekli koşulu kontrol ediyorsunuz (2 veya 3'e bölünebilirlik), ancak bu yeterli değil .
DanaJ

Güzel, bu özellik ile eşleşiyorsunuz: 3'ten büyük her asal sayı 6n + 1 veya 6n + 5 biçimindedir, ancak 6n + 1 veya 6n + 5 biçiminde sayılar vardır (25 olarak), ancak bunlar asal değil
Luis Felipe

0

Hızlı bir doğrulama yapmak zorunda kaldığımda, bu basit kodu girdinin karekökünden daha küçük sayılar arasındaki temel bölünmeye dayanarak yazıyorum.

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)
  • Sonuncusu True != n==1davanın önlenmesin=1 .
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.