Algoritme manakah yang tercepat untuk menemukan bilangan prima?


183

Manakah algoritma tercepat untuk mengetahui bilangan prima menggunakan C ++? Saya telah menggunakan algoritme saringan tetapi saya tetap menginginkannya lebih cepat!


Artikel lama yang saya temukan, tetapi terlihat menarik: Bersenang-senang dengan Prime Numbers
Mvcoile

29
@ Pemeriksa ini gagal untuk nomor serendah 7 (111). Itu juga gagal untuk 1001 = 9. Dan jelas itu gagal untuk hampir semua bilangan prima secara umum (tidak mencakup kasus 2 ^ p - 1, yang merupakan bilangan prima Mersenne - contoh klasik yang dihasilkan - yang akan selalu dalam bentuk 111 ... 1)
Daniel Kats

1
@Kasperasky - Anda tidak menyebutkan Saringan mana? Anda mungkin maksud Saringan Eranthosis!
user2618142

Algoritma Saringan Eratosthenes
Emad Aghayi

Jawaban:


79

Implementasi yang sangat cepat dari Saringan Atkin adalah primegen Dan Bernstein . Saringan ini lebih efisien daripada Saringan Eratosthenes . Halamannya memiliki beberapa informasi benchmark.


10
Sebenarnya saya tidak berpikir primegen adalah yang tercepat, atau bahkan yang tercepat kedua; yafu dan primesieve keduanya lebih cepat secara umum, saya pikir, dan tentu saja lebih dari 2 ^ 32. Keduanya adalah saringan Eratosthenes (yang dimodifikasi) dan bukan saringan Atkin-Bernstein.
Charles

5
Primesieve Sieve of Eratosthenes (SoE) adalah algoritma paling cepat yang mungkin dan akan selalu lebih cepat daripada implementasi Saringan Atkin SoA, termasuk Bernstein terkait dalam jawaban ini karena primesieve mengurangi jumlah operasi dibandingkan dengan SoA: Untuk 32- bit number range (2 ^ 32 - 1), primesieve melakukan sekitar 1,2 miliar culls sedangkan SoA melakukan total sekitar 1,4 miliar gabungan operasi toggle dan square, keduanya operasi yang memiliki kompleksitas yang sama dan dapat dioptimalkan dalam waktu yang hampir sama cara.
GordonBGood

7
Lanjutan: Bernstein hanya membandingkan SoE menggunakan faktorisasi roda efektif yang sama seperti untuk SoA, yang merupakan roda 2; 3; 5, yang penggunaannya menghasilkan sekitar 1,83 miliar culls pada rentang angka 32-bit; ini membuat SoA sekitar 30% lebih cepat ketika membandingkan versi SoE terbatas ini untuk optimasi lain yang setara. Namun, algoritma primesieve menggunakan roda 2; 3; 5; 7 dikombinasikan dengan pre-cull segmen roda 2; 3; 5; 7; 11; 13; 17 untuk mengurangi jumlah operasi menjadi sekitar 1,2 miliar untuk menjalankan sekitar 16,7% lebih cepat dari SoA dengan optimisasi loop operasi yang setara.
GordonBGood

6
Lanjutan2: SoA con tidak memiliki faktorisasi roda faktor yang lebih tinggi digunakan untuk membuat banyak perbedaan sebagai roda faktorisasi 2; 3; 5 adalah bagian "dipanggang" dalam algoritma.
GordonBGood

4
@Eamon Nerbonne, WP benar; Namun, hanya memiliki kompleksitas komputasi yang sedikit lebih baik tidak membuat algoritma lebih cepat untuk penggunaan umum. Dalam komentar-komentar ini, saya merujuk pada faktorisasi roda maksimum Saringan Eratosthenes (SoE) (yang tidak mungkin untuk Saringan Atkin-SoA) membuat operasi yang sedikit lebih sedikit untuk SoE hingga kisaran sekitar satu miliar. Jauh di atas titik itu, seseorang umumnya perlu menggunakan segmentasi halaman untuk mengatasi keterbatasan memori, dan di situlah SoA gagal, mengambil jumlah overhead konstan yang meningkat dengan kisaran yang meningkat.
GordonBGood

29

Jika harus sangat cepat, Anda dapat memasukkan daftar bilangan prima:
http://www.bigprimes.net/archive/prime/

Jika Anda hanya perlu tahu apakah angka tertentu adalah bilangan prima, ada berbagai tes prima yang terdaftar di wikipedia . Mereka mungkin merupakan metode tercepat untuk menentukan apakah angka besar adalah bilangan prima, terutama karena mereka dapat memberi tahu Anda jika angka bukanlah bilangan prima.


2
Daftar semua bilangan prima? Saya pikir Anda berarti daftar beberapa bilangan prima pertama ... :)
j_random_hacker

9
Jika Anda menelepon beberapa 10.000.000, maka ya. :)
Georg Schölly

58
pasti 100000000 adalah "sedikit" dibandingkan dengan tak terbatas;)
Timofey

9
Mengapa Anda berpikir bahwa Saringan Atkin (SoA) lebih cepat daripada Saringan Eratosthenes (SoE)? Tentunya tidak ketika seseorang hanya mengimplementasikan program menggunakan kode semu seperti pada artikel Wikipedia yang Anda tautkan. Jika SoE diimplementasikan dengan tingkat kemungkinan optimasi yang sama seperti yang digunakan dengan SoA, maka ada sedikit operasi untuk rentang saringan yang sangat besar untuk SoA daripada untuk SoE, tetapi kenaikan itu biasanya lebih dari diimbangi oleh peningkatan kompleksitas dan overhead faktor ekstra konstan dari kompleksitas komputasi ini sehingga untuk aplikasi praktis, SoE lebih baik.
GordonBGood

26

He, he I know I'm a pertanyaan ahli nujum menjawab pertanyaan-pertanyaan lama, tapi saya baru saja menemukan pertanyaan ini mencari di internet cara untuk menerapkan tes bilangan prima yang efisien.

Sampai sekarang, saya percaya bahwa algoritma pengujian bilangan prima tercepat adalah Strong Probable Prime (SPRP). Saya mengutip dari forum Nvidia CUDA:

Salah satu masalah ceruk yang lebih praktis dalam teori bilangan berkaitan dengan identifikasi bilangan prima. Mengingat N, bagaimana Anda bisa menentukan secara efisien apakah itu prima atau tidak? Ini bukan hanya masalah thoeretical, itu mungkin masalah nyata yang dibutuhkan dalam kode, mungkin ketika Anda perlu secara dinamis menemukan ukuran tabel hash utama dalam rentang tertentu. Jika N adalah sesuatu dengan urutan 2 ^ 30, apakah Anda benar-benar ingin melakukan 30000 tes pembagian untuk mencari faktor apa pun? Tentu saja tidak.

Solusi praktis umum untuk masalah ini adalah tes sederhana yang disebut Euler probable prime test, dan generalisasi yang lebih kuat yang disebut Strong Probable Prime (SPRP). Ini adalah tes yang untuk bilangan bulat N secara probabilistik dapat mengklasifikasikannya sebagai bilangan prima atau tidak, dan tes berulang dapat meningkatkan probabilitas kebenaran. Bagian lambat dari tes itu sendiri sebagian besar melibatkan perhitungan nilai yang mirip dengan modul A ^ (N-1) N. Siapa pun yang menerapkan varian enkripsi kunci publik RSA telah menggunakan algoritma ini. Ini berguna baik untuk bilangan bulat besar (seperti 512 bit) maupun ints normal 32 atau 64 bit.

Tes ini dapat diubah dari penolakan probabilistik menjadi bukti definitif primality dengan mengkomputasi parameter input tes tertentu yang diketahui selalu berhasil untuk rentang N. Sayangnya penemuan "tes paling terkenal" ini secara efektif adalah pencarian yang besar ( sebenarnya infinite) domain. Pada tahun 1980, daftar pertama dari tes yang berguna dibuat oleh Carl Pomerance (terkenal karena menjadi faktor RSA-129 dengan algoritma Quadratic Seive-nya.) Kemudian Jaeschke meningkatkan hasil secara signifikan pada tahun 1993. Pada tahun 2004, Zhang dan Tang meningkatkan teorinya. dan batas-batas domain pencarian. Greathouse dan Livingstone telah merilis hasil paling modern hingga sekarang di web, di http://math.crg4.com/primes.html , hasil terbaik dari domain pencarian yang sangat besar.

Lihat di sini untuk info lebih lanjut: http://primes.utm.edu/prove/prove2_3.html dan http://forums.nvidia.com/index.php?showtopic=70483

Jika Anda hanya membutuhkan cara untuk menghasilkan bilangan prima yang sangat besar dan tidak peduli untuk menghasilkan semua bilangan prima <bilangan bulat, Anda dapat menggunakan uji Lucas-Lehmer untuk memverifikasi bilangan prima Mersenne. Bilangan prima Mersenne adalah dalam bentuk 2 ^ p -1. Saya berpikir bahwa uji Lucas-Lehmer adalah algoritma tercepat yang ditemukan untuk bilangan prima Mersenne.

Dan jika Anda tidak hanya ingin menggunakan algoritma tercepat tetapi juga perangkat keras tercepat, cobalah untuk mengimplementasikannya menggunakan Nvidia CUDA, tulis kernel untuk CUDA dan jalankan di GPU.

Anda bahkan dapat memperoleh uang jika Anda menemukan bilangan prima yang cukup besar, EFF memberikan hadiah mulai dari $ 50 ribu hingga $ 250 ribu: https://www.eff.org/awards/coop


17

Ada tes matematika 100% yang akan memeriksa apakah suatu bilangan Pprima atau gabungan, yang disebut AKS Primality Test .

Konsepnya sederhana: diberi angka P, jika semua koefisien (x-1)^P - (x^P-1)dapat dibagi dengan P, maka Padalah bilangan prima, jika tidak maka itu adalah bilangan komposit.

Misalnya, diberikan P = 3, akan memberikan jumlahnya banyak:

   (x-1)^3 - (x^3 - 1)
 = x^3 + 3x^2 - 3x - 1 - (x^3 - 1)
 = 3x^2 - 3x

Dan koefisien keduanya habis dibagi 3, oleh karena itu jumlahnya prima.

Dan contoh di mana P = 4, yang BUKAN bilangan prima akan menghasilkan:

   (x-1)^4 - (x^4-1)
 = x^4 - 4x^3 + 6x^2 - 4x + 1 - (x^4 - 1)
 = -4x^3 + 6x^2 - 4x

Dan di sini kita dapat melihat bahwa koefisien 6tidak habis dibagi 4, oleh karena itu BUKAN prima.

Polinomial (x-1)^Pakan P+1terma dan dapat ditemukan menggunakan kombinasi. Jadi, tes ini akan berjalan dalam O(n)runtime, jadi saya tidak tahu seberapa berguna ini karena Anda dapat dengan mudah beralih idari 0 ke pdan menguji sisanya.


5
AKS adalah metode yang sangat lambat dalam praktiknya, tidak bersaing dengan metode lain yang dikenal. Metode yang Anda gambarkan bukanlah AKS tetapi lemma pembuka yang lebih lambat daripada pembagian percobaan yang tidak dioptimalkan (seperti yang Anda tunjukkan).
DanaJ

halo @ Kousha, untuk apa xsingkatannya? di (x-1)^P - (x^P-1). apakah Anda memiliki kode sampel untuk ini? di C ++ untuk menentukan apakah integer prima atau tidak?
kiLLua

@kiLLua X hanyalah sebuah variabel. Koefisien X yang menentukan apakah bilangan prima atau tidak. Dan tidak, saya tidak memiliki kode. Saya tidak merekomendasikan untuk menggunakan metode ini untuk menentukan apakah suatu bilangan prima atau tidak. Ini hanya perilaku matematika bilangan prima yang sangat keren, tetapi sebaliknya itu sangat tidak efisien.
Kousha

5

Apakah masalah Anda untuk memutuskan apakah nomor tertentu prima? Maka Anda perlu tes primality (mudah). Atau apakah Anda membutuhkan semua bilangan prima hingga nomor tertentu? Dalam hal ini saringan utama bagus (mudah, tetapi membutuhkan memori). Atau apakah Anda memerlukan faktor utama nomor? Ini akan membutuhkan faktorisasi (sulit untuk jumlah besar jika Anda benar-benar menginginkan metode yang paling efisien). Seberapa besar angka yang Anda lihat? 16 bit? 32 bit? lebih besar?

Salah satu cara cerdas dan efisien adalah dengan pra-menghitung tabel bilangan prima dan menyimpannya dalam file menggunakan pengodean bit-level. File dianggap sebagai satu vektor bit panjang sedangkan bit n mewakili integer n. Jika n adalah prima, bitnya disetel ke satu dan ke nol sebaliknya. Pencarian sangat cepat (Anda menghitung byte offset dan bit mask) dan tidak perlu memuat file dalam memori.


Tes primality yang baik bersaing dengan latensi memori utama untuk tabel utama yang cukup masuk akal, jadi saya tidak akan menggunakan ini kecuali bisa masuk ke L2.
Charles

3

Rabin-Miller adalah tes primality probabilistik standar. (Anda menjalankannya K kali dan nomor input pasti komposit, atau mungkin prima dengan probabilitas kesalahan 4- K . (beberapa ratus iterasi dan hampir pasti mengatakan yang sebenarnya)

Ada varian non-probabilistik (deterministik) dari Rabin Miller .

The Great Internet Mersenne Prime Search (GIMPS) yang telah menemukan rekor dunia untuk perdana terbesar terbukti (2 74.207.281 - 1 pada Juni 2017), menggunakan beberapa algoritma , tetapi ini adalah bilangan prima dalam bentuk khusus. Namun halaman GIMPS di atas memang menyertakan beberapa tes primality deterministik umum. Mereka muncul untuk menunjukkan bahwa algoritma mana yang "tercepat" tergantung pada ukuran angka yang akan diuji. Jika nomor Anda pas di 64 bit maka Anda mungkin tidak harus menggunakan metode yang dimaksudkan untuk bekerja pada bilangan prima beberapa juta digit.


2

Itu tergantung pada aplikasi Anda. Ada beberapa pertimbangan:

  • Apakah Anda hanya memerlukan informasi apakah beberapa bilangan prima, apakah Anda memerlukan semua bilangan prima hingga batas tertentu, atau apakah Anda memerlukan (berpotensi) semua bilangan prima?
  • Seberapa besar angka yang harus Anda tangani?

Miller-Rabin dan tes analog hanya lebih cepat dari ayakan untuk angka lebih dari ukuran tertentu (sekitar beberapa juta, saya percaya). Di bawah itu, menggunakan divisi percobaan (jika Anda hanya memiliki beberapa angka) atau ayakan lebih cepat.


0

Saya akan membiarkan Anda memutuskan apakah ini yang tercepat atau tidak.

using System;
namespace PrimeNumbers
{

public static class Program
{
    static int primesCount = 0;


    public static void Main()
    {
        DateTime startingTime = DateTime.Now;

        RangePrime(1,1000000);   

        DateTime endingTime = DateTime.Now;

        TimeSpan span = endingTime - startingTime;

        Console.WriteLine("span = {0}", span.TotalSeconds);

    }


    public static void RangePrime(int start, int end)
    {
        for (int i = start; i != end+1; i++)
        {
            bool isPrime = IsPrime(i);
            if(isPrime)
            {
                primesCount++;
                Console.WriteLine("number = {0}", i);
            }
        }
        Console.WriteLine("primes count = {0}",primesCount);
    }



    public static bool IsPrime(int ToCheck)
    {

        if (ToCheck == 2) return true;
        if (ToCheck < 2) return false;


        if (IsOdd(ToCheck))
        {
            for (int i = 3; i <= (ToCheck / 3); i += 2)
            {
                if (ToCheck % i == 0) return false;
            }
            return true;
        }
        else return false; // even numbers(excluding 2) are composite
    }

    public static bool IsOdd(int ToCheck)
    {
        return ((ToCheck % 2 != 0) ? true : false);
    }
}
}

Diperlukan sekitar 82 detik untuk menemukan dan mencetak bilangan prima dalam kisaran 1 hingga 1.000.000, pada laptop Core 2 Duo saya dengan prosesor 2,40 GHz. Dan ditemukan 78.498 bilangan prima.


3
ini terlalu lambat. masalahnya adalah i <= (ToCheck / 3). seharusnya begitu i <= (ToCheck / i). dengan itu, itu mungkin berjalan dalam 0,1 detik saja.
Will Ness

-1

Saya selalu menggunakan metode ini untuk menghitung bilangan primes mengikuti dengan algoritma ayakan.

void primelist()
 {
   for(int i = 4; i < pr; i += 2) mark[ i ] = false;
   for(int i = 3; i < pr; i += 2) mark[ i ] = true; mark[ 2 ] = true;
   for(int i = 3, sq = sqrt( pr ); i < sq; i += 2)
       if(mark[ i ])
          for(int j = i << 1; j < pr; j += i) mark[ j ] = false;
  prime[ 0 ] = 2; ind = 1;
  for(int i = 3; i < pr; i += 2)
    if(mark[ i ]) ind++; printf("%d\n", ind);
 }

-3
#include<stdio.h>
main()
{
    long long unsigned x,y,b,z,e,r,c;
    scanf("%llu",&x);
    if(x<2)return 0;
    scanf("%llu",&y);
    if(y<x)return 0;
    if(x==2)printf("|2");
    if(x%2==0)x+=1;
    if(y%2==0)y-=1;
    for(b=x;b<=y;b+=2)
    {
        z=b;e=0;
        for(c=2;c*c<=z;c++)
        {
            if(z%c==0)e++;
            if(e>0)z=3;
        }
        if(e==0)
        {
            printf("|%llu",z);
            r+=1;
        }
    }
    printf("|\n%llu outputs...\n",r);
    scanf("%llu",&r);
}    

r digunakan sebelum diinisialisasi
zumalifeguard

-3

Saya tidak tahu tentang algoritma yang telah ditentukan tetapi saya membuat sendiri yang sangat cepat. Itu dapat memproses 20 digit angka dalam waktu kurang dari 1 detik. Kemampuan maksimal program ini adalah 18446744073709551615. Program ini adalah:

#include <iostream>
#include <cmath>
#include <stdlib.h>

using namespace std;

unsigned long long int num = 0;

bool prime() {
    if (num % 2 == 0 || num == 1) {
        return false;
    }

    unsigned long int square_root = sqrt(num);
    for (unsigned long int i = 3; i <= square_root; i += 2) {
        if (num % i == 0) {
            return false;
        }
    }

    return true;
}

int main() {
    do {
        system("cls");
        cout << "Enter number : ";
        cin >> num;

        if (prime()) {
            cout << "The number is a prime number" << endl << endl << endl << endl;
        } else {
            cout << "The number is not a prime number" << endl << endl << endl << endl;
        }
        system("pause");
    } while (1);

    return 0;
}

-4
#include <iostream>

using namespace std;

int set [1000000];

int main (){

    for (int i=0; i<1000000; i++){
        set [i] = 0;
    }
    int set_size= 1000;
    set [set_size];
    set [0] = 2;
    set [1] = 3;
    int Ps = 0;
    int last = 2;

    cout << 2 << " " << 3 << " ";

    for (int n=1; n<10000; n++){
        int t = 0;
        Ps = (n%2)+1+(3*n);
        for (int i=0; i==i; i++){
            if (set [i] == 0) break;
            if (Ps%set[i]==0){
                t=1;
                break;
            }
        }
        if (t==0){
            cout << Ps << " ";
            set [last] = Ps;
            last++;
        }
    }
    //cout << last << endl;


    cout << endl;

    system ("pause");
    return 0;
}

12
ini harus menjadi jawaban pada "Cara menulis kode yang tidak terstruktur tanpa benar-benar menggunakan GOTO". Semua kebingungan ini hanya untuk kode divisi percobaan sederhana! (n%2)+1+(3*n)agak baik. :)
Will Ness

1
@ Akankah Ness saya akan menurunkan ini sebagai jawaban untuk pertanyaan itu; mengapa menggunakan for for ketika makro akan melakukannya? :)
Rob Grant

-4

Saya tahu ini agak terlambat, tetapi ini bisa bermanfaat bagi orang yang datang ke sini dari pencarian. Bagaimanapun, inilah beberapa JavaScript yang bergantung pada fakta bahwa hanya faktor prima yang perlu diuji, sehingga bilangan prima sebelumnya yang dihasilkan oleh kode tersebut digunakan kembali sebagai faktor pengujian untuk faktor-faktor selanjutnya. Tentu saja, semua nilai genap dan mod 5 disaring terlebih dahulu. Hasilnya akan berada di array P, dan kode ini dapat menghasilkan 10 juta bilangan prima dalam waktu kurang dari 1,5 detik pada PC i7 (atau 100 juta dalam sekitar 20). Ditulis ulang dalam C itu harus sangat cepat.

var P = [1, 2], j, k, l = 3

for (k = 3 ; k < 10000000 ; k += 2)
{
  loop: if (++l < 5)
  {
    for (j = 2 ; P[j] <= Math.sqrt(k) ; ++j)
      if (k % P[j] == 0) break loop

    P[P.length] = k
  }
  else l = 0
}

2
Ini akan memberi Anda banyak masalah jika Anda menghasilkan sejumlah besar bilangan prima, dan untuk perbandingan, lebih baik gunakan P [j] * P [j] <= k, karena sqrt sangat lambat
Simon

-11
#include<iostream>
using namespace std;

void main()
{
    int num,i,j,prime;
    cout<<"Enter the upper limit :";
    cin>>num;

    cout<<"Prime numbers till "<<num<<" are :2, ";

    for(i=3;i<=num;i++)
    {
        prime=1;
        for(j=2;j<i;j++)
        {
            if(i%j==0)
            {
                prime=0;
                break;
            }
        }

        if(prime==1)
            cout<<i<<", ";

    }
}

60
ini tentang yang paling lambat yang bisa Anda lakukan.
Will Ness

1
Ini sangat lambat, jika batas atas misalkan 10.000.000 maka kode ini akan menghabiskan banyak waktu !!
Dixit Singla

kode ini adalah O (N ^ 2 / log N). tanpa break;itu akan lebih lambat, O (N ^ 2), tapi itu sudah bisa dilihat sebagai kesalahan pengkodean. menyimpan dan menguji dengan bilangan prima adalah O (N ^ 2 / (log N) ^ 2), dan pengujian dengan bilangan prima di bawah hanya akar kuadrat angka, adalah O (N ^ 1,5 / (log N) ^ 2).
Will Ness

@ WillNess Mungkin sedikit hiperbolik. Dia bisa dengan mudah memulai for for loop dari 1 bukannya 2, dan menambahkan j <= i bukannya j <i. :)
Kenny Cason

3
Saya tidak berpikir posting ini harus dihapus, itu berfungsi sebagai contoh balasan yang berharga.
Will Ness
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.