C ++ kullanarak asal sayıları bulmak için en hızlı algoritma hangisidir? Elek algoritmasını kullandım ama hala daha hızlı olmasını istiyorum!
C ++ kullanarak asal sayıları bulmak için en hızlı algoritma hangisidir? Elek algoritmasını kullandım ama hala daha hızlı olmasını istiyorum!
Yanıtlar:
Atkin Elekinin çok hızlı uygulanması Dan Bernstein'ın başbakanıdır . Bu elek Eratosthenes elekinden daha verimlidir . Sayfasında bazı karşılaştırma bilgileri var.
Gerçekten hızlı olması gerekiyorsa, bir asal sayı listesi ekleyebilirsiniz:
http://www.bigprimes.net/archive/prime/
Belirli bir sayının asal sayı olup olmadığını bilmeniz gerekiyorsa , wikipedia'da listelenen çeşitli asal testler vardır . Büyük sayıların asal olup olmadığını belirlemek için muhtemelen en hızlı yöntemdir, özellikle de bir sayının asal olmadığını söyleyebilirler .
O, eski sorulara cevap veren bir soru büyücüsü olduğumu biliyorum, ama bu soruyu, net asal sayı testleri yapmanın yollarını arayarak buldum.
Şimdiye kadar, en hızlı asal sayı test algoritmasının Güçlü Olası Başbakan (SPRP) olduğuna inanıyorum. Nvidia CUDA forumlarından alıntı yapıyorum:
Sayı teorisindeki daha pratik niş sorunlarından biri asal sayıların tanımlanmasıyla ilgilidir. N verildiğinde, asal olup olmadığını nasıl verimli bir şekilde belirleyebilirsiniz? Bu sadece eterik bir sorun değildir, belki de belirli aralıklarda dinamik bir asal tablo boyutu bulmanız gerektiğinde, kodda gerçek bir sorun olabilir. N, 2 ^ 30 düzeyindeki bir şeyse, herhangi bir faktörü aramak için gerçekten 30000 bölüm testi yapmak ister misiniz? Belli ki değil.
Bu sorunun ortak pratik çözümü, Euler olası ana testi adı verilen basit bir test ve Güçlü Olası Başbakan (SPRP) adı verilen daha güçlü bir genellemedir. Bu, bir tamsayı N için onu olasılıkla birincil olarak sınıflandırıp sınıflandıramayacağı ve tekrarlanan testlerin doğruluk olasılığını artırabileceği bir testtir. Testin yavaş kısmı çoğunlukla A ^ (N-1) modulo N'ye benzer bir değer hesaplamayı içerir. RSA ortak anahtar şifreleme varyantlarını uygulayan herkes bu algoritmayı kullanmıştır. Hem büyük tam sayılar (512 bit gibi) hem de normal 32 veya 64 bit ints için yararlıdır.
Test, N aralıkları için her zaman başarılı olduğu bilinen bazı test giriş parametrelerini önceden hesaplayarak, olasılıkla reddedilmenin kesin bir ilkel kanıtına dönüştürülebilir. Ne yazık ki bu "en iyi bilinen testlerin" keşfi, büyük bir ( aslında sonsuz). 1980'de Carl Pomerance tarafından (Kuadratik Seive algoritmasıyla RSA-129'u faktör olarak kabul ettiği için ünlü) ilk yararlı testler listesi oluşturuldu. Daha sonra Jaeschke 1993'te sonuçları önemli ölçüde geliştirdi. 2004'te Zhang ve Tang teoriyi geliştirdi ve arama alanının sınırları. Greathouse ve Livingstone, bugüne kadar web'de en modern sonuçları , büyük bir arama alanının en iyi sonuçları olan http://math.crg4.com/primes.html adresinde yayınladı .
Daha fazla bilgi için buraya bakın: http://primes.utm.edu/prove/prove2_3.html ve http://forums.nvidia.com/index.php?showtopic=70483
Sadece çok büyük asal sayılar üretmenin bir yoluna ihtiyacınız varsa ve tüm asal sayılar <bir tamsayı n üretmekle ilgilenmiyorsanız, Mersenne asal sayılarını doğrulamak için Lucas-Lehmer testini kullanabilirsiniz. Bir Mersenne asal numarası 2 ^ p -1 biçimindedir. Ben Lucas-Lehmer testinin Mersenne asal sayıları için keşfedilen en hızlı algoritma olduğunu düşünüyorum.
Ve sadece en hızlı algoritmayı değil, aynı zamanda en hızlı donanımı da kullanmak istiyorsanız, Nvidia CUDA kullanarak uygulamayı deneyin, CUDA için bir çekirdek yazın ve GPU'da çalıştırın.
Yeterince büyük asal sayılar bulursanız bile para kazanabilirsiniz, EFF 50 bin dolardan 250 bin dolara kadar ödül veriyor: https://www.eff.org/awards/coop
AKS Primality Test olarakP
adlandırılan bir sayının asal veya kompozit olup olmadığını kontrol edecek% 100 matematiksel bir test vardır .
Kavram basittir: bir sayı verildiğinde P
, tüm katsayıları (x-1)^P - (x^P-1)
ile bölünebilirse P
, o zaman P
asal bir sayıdır, aksi takdirde bileşik bir sayıdır.
Örneğin, verilen P = 3
, polinomu verir:
(x-1)^3 - (x^3 - 1)
= x^3 + 3x^2 - 3x - 1 - (x^3 - 1)
= 3x^2 - 3x
Ve katsayıların her ikisi de bölünebilir 3
, bu nedenle sayı asaldır.
Ve P = 4
asal olmayan DEĞİL nerede örnek :
(x-1)^4 - (x^4-1)
= x^4 - 4x^3 + 6x^2 - 4x + 1 - (x^4 - 1)
= -4x^3 + 6x^2 - 4x
Ve burada katsayıların 6
bölünemez olmadığını görebiliriz 4
, bu nedenle birincil değildir.
Polinom (x-1)^P
irade P+1
şart ve kombinasyonu kullanılarak bulunabilir. Yani, bu test O(n)
çalışma zamanında çalışacaktır , bu yüzden sadece i
0'dan daha fazla yineleyebildiğiniz p
ve geri kalanını test edebildiğiniz için bunun ne kadar yararlı olacağını bilmiyorum .
x
? içinde (x-1)^P - (x^P-1)
. bunun için örnek bir kod var mı? tam sayı asal olup olmadığını belirlemek için C ++?
Sorununuz belirli bir sayının asal olup olmadığına karar vermek mi? O zaman bir öncelik testine ihtiyacınız var (kolay). Yoksa belirli bir sayıya kadar tüm asal sayılara mı ihtiyacınız var? Bu durumda ana elekler iyidir (kolay, ancak bellek gerektirir). Veya bir sayının asal faktörlerine mi ihtiyacınız var? Bu, çarpanlara ayırmayı gerektirir (gerçekten en verimli yöntemleri istiyorsanız büyük sayılar için zor). Hangi rakamlara bakıyorsunuz? 16 bit? 32 bit? Daha büyük?
Akıllı ve etkili bir yol, asal tabloları önceden hesaplamak ve bit düzeyinde kodlama kullanarak bir dosyada tutmaktır. Dosya bir uzun bit vektörü olarak kabul edilirken, n biti n tamsayısını temsil eder. N asal ise, biti bire ve sıfır olarak ayarlanır. Arama çok hızlıdır (bayt uzaklığını ve bit maskesini hesaplarsınız) ve dosyanın belleğe yüklenmesini gerektirmez.
Rabin-Miller standart bir olasılıksal öncelik testidir. (K kez çalıştırırsınız ve giriş numarası kesinlikle kompozittir veya muhtemelen 4 -K hata olasılığı ile asaldır . (birkaç yüz yineleme ve neredeyse kesinlikle gerçeği söyler)
Rabin Miller'ın olasılık dışı (deterministik) bir çeşidi vardır .
Büyük İnternet Mersenne Prime Arama büyük kanıtlanmış asal için dünya rekoru bulmuştur (gimps) (2 74207281 - Haziran 2017 tarihi itibariyle 1) kullanır çeşitli algoritmalar , ama bu özel formlarda Asal sayılar. Bununla birlikte, yukarıdaki GIMPS sayfası bazı genel deterministik öncelik testleri içerir. Hangi algoritmanın "en hızlı" olduğunu, test edilecek sayının boyutuna bağlı olduğunu belirtiyorlar. Numaranız 64 bit'e uyuyorsa, muhtemelen birkaç milyon basamaklı primerlerde çalışmak için bir yöntem kullanmamalısınız.
Uygulamanıza bağlıdır. Bazı düşünceler var:
Miller-Rabin ve analog testleri, belirli bir büyüklükteki sayılar için sadece bir elekten daha hızlıdır (birkaç milyon civarında bir yere inanıyorum). Bunun altında, bir deneme bölümü (sadece birkaç numaranız varsa) veya bir elek kullanmak daha hızlıdır.
En hızlı olup olmadığına karar vermene izin vereceğim.
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);
}
}
}
2,40 GHz işlemcili Core 2 Duo dizüstü bilgisayarımda 1 ila 1,000,000 aralığında asal sayıları bulmak ve yazdırmak yaklaşık 82 saniye sürer . Ve 78.498 asal sayı buldu .
i <= (ToCheck / 3)
. olmalı i <= (ToCheck / i)
. onunla, bunun yerine 0.1 saniye içinde çalışabilir.
Her zaman elek algoritması ile takip eden asal sayıları hesaplamak için bu yöntemi kullanıyorum.
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);
}
Önceden tanımlanmış herhangi bir algoritma bilmiyorum ama çok hızlı olan kendi algoritmamı oluşturdum. 1 saniyeden daha kısa sürede 20 basamaklı sayıları işleyebilir. Bu programın maksimum kapasitesi 18446744073709551615'dir. Program:
#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)
gerçi güzel. :)
Biraz sonra olduğunu biliyorum, ama bu aramalardan gelen insanlar için yararlı olabilir. Her neyse, burada sadece asal faktörlerin test edilmesi gerektiğine dayanan bazı JavaScriptler var, bu nedenle kod tarafından oluşturulan önceki asal değerler daha sonraki olanlar için test faktörleri olarak yeniden kullanılıyor. Tabii ki, önce tüm çift ve mod 5 değerleri filtrelenir. Sonuç P dizisinde olacaktır ve bu kod bir i7 PC'de (veya yaklaşık 20'de 100 milyon) 1,5 saniyenin altında 10 milyon primu kırabilir. C'de yeniden yazıldığında çok hızlı olmalı.
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;
daha yavaş olurdu, O (N ^ 2), ama bu zaten bir kodlama hatası olarak görülebilirdi. primerlerle kaydetme ve test etme O (N ^ 2 / (log N) ^ 2) ve sadece sayının kare kökünün altındaki primerlerle test O (N ^ 1.5 / (log N) ^ 2).