Qual è l'algoritmo più veloce per scoprire i numeri primi usando C ++? Ho usato l'algoritmo di Sieve ma voglio ancora che sia più veloce!
Qual è l'algoritmo più veloce per scoprire i numeri primi usando C ++? Ho usato l'algoritmo di Sieve ma voglio ancora che sia più veloce!
Risposte:
Un'implementazione molto rapida del setaccio di Atkin è il primegen di Dan Bernstein . Questo setaccio è più efficiente del setaccio di Eratostene . La sua pagina contiene alcune informazioni di riferimento.
Se deve essere molto veloce, puoi includere un elenco di numeri primi:
http://www.bigprimes.net/archive/prime/
Se devi solo sapere se un certo numero è un numero primo, ci sono vari test primi elencati su Wikipedia . Sono probabilmente il metodo più veloce per determinare se numeri grandi sono numeri primi, soprattutto perché possono dirti se un numero non è un numero primo.
Lui, lui so di essere un negromante che risponde a vecchie domande, ma ho appena trovato questa domanda cercando in rete modi per implementare test efficaci sui numeri primi.
Fino ad ora, credo che l'algoritmo di test dei numeri primi più veloce sia Strong Probable Prime (SPRP). Sto citando dai forum Nvidia CUDA:
Uno dei problemi di nicchia più pratici nella teoria dei numeri ha a che fare con l'identificazione dei numeri primi. Dato N, come si può determinare in modo efficiente se è primo o no? Questo non è solo un problema teorico, può essere un problema reale necessario nel codice, forse quando è necessario trovare dinamicamente una dimensione della tabella hash primaria all'interno di determinati intervalli. Se N è qualcosa nell'ordine di 2 ^ 30, vuoi davvero fare 30000 test di divisione per cercare qualche fattore? Ovviamente no.
La soluzione pratica comune a questo problema è un semplice test chiamato probabile primo test di Eulero e una generalizzazione più potente chiamata Strong Probable Prime (SPRP). Questo è un test che per un numero intero N può classificarlo probabilisticamente come primo o no, e test ripetuti possono aumentare la probabilità di correttezza. La parte lenta del test stesso comporta principalmente il calcolo di un valore simile a A ^ (N-1) modulo N. Chiunque implementasse varianti di crittografia a chiave pubblica RSA ha utilizzato questo algoritmo. È utile sia per numeri interi enormi (come 512 bit) sia per normali 32 o 64 bit.
Il test può essere modificato da un rifiuto probabilistico in una prova definitiva di primalità precompilando alcuni parametri di input del test che sono noti per avere sempre successo per intervalli di N. Sfortunatamente la scoperta di questi "test più noti" è effettivamente una ricerca di un enorme ( in realtà infinito) dominio. Nel 1980, Carl Pomerance ha creato un primo elenco di test utili (famoso per essere il fattore con cui RSA-129 è stato col suo algoritmo Quadratic Seive.) Successivamente Jaeschke ha migliorato significativamente i risultati nel 1993. Nel 2004, Zhang e Tang hanno migliorato la teoria e limiti del dominio di ricerca. Greathouse e Livingstone hanno pubblicato i risultati più moderni fino ad ora sul Web, su http://math.crg4.com/primes.html , i migliori risultati di un enorme dominio di ricerca.
Vedi qui per maggiori informazioni: http://primes.utm.edu/prove/prove2_3.html e http://forums.nvidia.com/index.php?showtopic=70483
Se hai solo bisogno di un modo per generare numeri primi molto grandi e non ti interessa generare tutti i numeri primi <un numero intero n, puoi utilizzare il test Lucas-Lehmer per verificare i numeri primi di Mersenne. Un numero primo di Mersenne ha la forma di 2 ^ p -1. Penso che il test di Lucas-Lehmer sia l'algoritmo più veloce scoperto per i numeri primi di Mersenne.
E se non vuoi solo usare l'algoritmo più veloce ma anche l'hardware più veloce, prova a implementarlo usando Nvidia CUDA, scrivi un kernel per CUDA ed eseguilo su GPU.
Puoi anche guadagnare un po 'di soldi se scopri numeri primi abbastanza grandi, EFF offre premi da $ 50K a $ 250K: https://www.eff.org/awards/coop
Esiste un test matematico al 100% che verificherà se un numero P
è primo o composito, chiamato AKS Primality Test .
Il concetto è semplice: dato un numero P
, se tutti i coefficienti di (x-1)^P - (x^P-1)
sono divisibili per P
, allora P
è un numero primo, altrimenti è un numero composto.
Ad esempio, dato P = 3
, darebbe il polinomio:
(x-1)^3 - (x^3 - 1)
= x^3 + 3x^2 - 3x - 1 - (x^3 - 1)
= 3x^2 - 3x
E i coefficienti sono entrambi divisibili per 3
, quindi il numero è primo.
Ed esempio dove P = 4
, che NON è un numero primo, si otterrebbe:
(x-1)^4 - (x^4-1)
= x^4 - 4x^3 + 6x^2 - 4x + 1 - (x^4 - 1)
= -4x^3 + 6x^2 - 4x
E qui possiamo vedere che i coefficienti 6
non sono divisibili per4
, quindi NON sono primi.
Il polinomio (x-1)^P
volontà P+1
termini e possono essere trovati tramite combinazione. Quindi, questo test verrà eseguito in O(n)
fase di esecuzione, quindi non so quanto sarebbe utile dal momento che puoi semplicemente scorrere i
da 0 a p
e testare il resto.
x
significa? in (x-1)^P - (x^P-1)
. hai un codice di esempio per questo? in C ++ per determinare se il numero intero è primo o no?
Il tuo problema è decidere se un determinato numero è primo? Quindi è necessario un test di primalità (facile). O hai bisogno di tutti i numeri primi fino a un determinato numero? In tal caso i setacci primi sono buoni (facili, ma richiedono memoria). O hai bisogno dei fattori primi di un numero? Ciò richiederebbe la fattorizzazione (difficile per grandi numeri se si vogliono davvero i metodi più efficienti). Quanto sono grandi i numeri che stai guardando? 16 bit? 32 bit? più grande?
Un modo intelligente ed efficiente è pre-calcolare tabelle di numeri primi e tenerli in un file usando una codifica a livello di bit. Il file è considerato un vettore di bit lungo mentre il bit n rappresenta l'intero n. Se n è primo, il suo bit è impostato su uno e su zero altrimenti. La ricerca è molto veloce (si calcola l'offset di byte e una maschera di bit) e non richiede il caricamento del file in memoria.
Rabin-Miller è un test probabilistico standard di primalità. (lo esegui K volte e il numero di input è sicuramente composito, oppure è probabilmente primo con probabilità di errore 4 -K . (poche centinaia di iterazioni e quasi sicuramente ti sta dicendo la verità)
Esiste una variante non probabilistica (deterministica) di Rabin Miller .
La Great Internet Mersenne Prime Search (GIMPS), che ha trovato il record mondiale per il numero primo più grande provato (2 74.207.281 - 1 a giugno 2017), utilizza diversi algoritmi , ma questi sono numeri primi in forme speciali. Tuttavia, la pagina GIMPS sopra include alcuni test di primalità deterministica generale. Sembrano indicare che l'algoritmo "più veloce" dipende dalla dimensione del numero da testare. Se il tuo numero si adatta a 64 bit, probabilmente non dovresti usare un metodo destinato a lavorare con numeri primi di diversi milioni di cifre.
Dipende dalla tua applicazione. Vi sono alcune considerazioni:
I test di Miller-Rabin e analogici sono solo più veloci di un setaccio per numeri di una certa dimensione (credo che siano circa qualche milione circa). Al di sotto di ciò, utilizzare una divisione di prova (se hai solo pochi numeri) o un setaccio è più veloce.
Ti lascerò decidere se è il più veloce o no.
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);
}
}
}
Sono necessari circa 82 secondi per trovare e stampare numeri primi in un intervallo compreso tra 1 e 1.000.000, sul mio laptop Core 2 Duo con un processore da 2,40 GHz. E ha trovato 78.498 numeri primi.
i <= (ToCheck / 3)
. dovrebbe essere i <= (ToCheck / i)
. con esso, invece, potrebbe essere eseguito in 0,1 secondi.
Uso sempre questo metodo per calcolare i numeri dei numeri primi che seguono con l'algoritmo del setaccio.
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);
}
#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);
}
Non conosco alcun algoritmo predefinito ma ne ho creato uno mio che è molto veloce. Può elaborare numeri di 20 cifre in meno di 1 secondo. La capacità massima di questo programma è 18446744073709551615. Il programma è:
#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;
}
#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;
}
(n%2)+1+(3*n)
è carino però. :)
So che è un po 'più tardi, ma questo potrebbe essere utile per le persone che arrivano qui dalle ricerche. Comunque, ecco alcuni JavaScript che si basano sul fatto che devono essere testati solo i fattori primi, quindi i primi precedenti generati dal codice vengono riutilizzati come fattori di test per quelli successivi. Naturalmente, tutti i valori pari e mod 5 vengono prima filtrati. Il risultato sarà nell'array P e questo codice può sgranocchiare 10 milioni di numeri primi in meno di 1,5 secondi su un PC i7 (o 100 milioni in circa 20). Riscritto in C dovrebbe essere molto veloce.
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
}
#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<<", ";
}
}
break;
sarebbe ancora più lento, O (N ^ 2), ma questo potrebbe già essere visto come un errore di codifica. il salvataggio e il test con numeri primi è O (N ^ 2 / (log N) ^ 2) e il test con numeri primi solo sotto la radice quadrata del numero, è O (N ^ 1.5 / (log N) ^ 2).