อัลกอริทึมที่เร็วที่สุดในการค้นหาหมายเลขเฉพาะด้วย C ++ คืออะไร ฉันใช้อัลกอริทึมของตะแกรง แต่ฉันยังต้องการให้เร็วขึ้น!
อัลกอริทึมที่เร็วที่สุดในการค้นหาหมายเลขเฉพาะด้วย C ++ คืออะไร ฉันใช้อัลกอริทึมของตะแกรง แต่ฉันยังต้องการให้เร็วขึ้น!
คำตอบ:
การดำเนินไปอย่างรวดเร็วมากของตะแกรงของแอทคินแดน Bernstein ของprimegen ตะแกรงนี้จะมีประสิทธิภาพมากขึ้นกว่าตะแกรงของ Eratosthenes หน้าของเขามีข้อมูลมาตรฐานบางอย่าง
หากจะต้องเร็วมากคุณสามารถรวมรายการช่วงเวลา:
http://www.bigprimes.net/archive/prime/
หากคุณเพียงแค่ต้องรู้ว่าถ้าจำนวนหนึ่งเป็นจำนวนเฉพาะมีต่าง ๆการทดสอบที่สำคัญที่ระบุไว้ในวิกิพีเดีย อาจเป็นวิธีที่เร็วที่สุดในการพิจารณาว่าจำนวนมากนั้นเป็นเฉพาะช่วงเวลาหรือไม่โดยเฉพาะอย่างยิ่งเพราะพวกเขาสามารถบอกคุณได้ว่าจำนวนนั้นไม่ใช่จำนวนเฉพาะหรือไม่
เขาเขาฉันรู้ว่าฉันเป็นหมอผีคำถามตอบคำถามเก่า แต่ฉันเพิ่งพบคำถามนี้ค้นหาสุทธิเพื่อหาวิธีที่จะใช้การทดสอบหมายเลขเฉพาะที่มีประสิทธิภาพ
จนถึงตอนนี้ฉันเชื่อว่าอัลกอริทึมการทดสอบจำนวนเฉพาะที่เร็วที่สุดคือ Strong Probable Prime (SPRP) ฉันอ้างจากฟอรัม Nvidia CUDA:
หนึ่งในปัญหาเฉพาะที่ใช้งานได้จริงในทฤษฎีจำนวนนั้นเกี่ยวข้องกับการระบุหมายเลขเฉพาะ เมื่อพิจารณาจาก N คุณจะทราบได้อย่างมีประสิทธิภาพว่าดีหรือไม่? นี่ไม่ได้เป็นเพียงปัญหาที่เกิดขึ้นจริงมันอาจเป็นของจริงที่จำเป็นในโค้ดบางทีเมื่อคุณต้องการค้นหาขนาดแฮชของตารางที่สำคัญในช่วงที่กำหนด ถ้า N เป็นบางสิ่งบางอย่างตามคำสั่งของ 2 ^ 30 คุณต้องการทำการทดสอบ 30,000 ครั้งเพื่อค้นหาปัจจัยใด ๆ หรือไม่? เห็นได้ชัดว่าไม่
วิธีแก้ปัญหาที่ใช้งานได้จริงสำหรับปัญหานี้คือการทดสอบอย่างง่าย ๆ ที่เรียกว่าการทดสอบ Prime Prime ที่น่าจะเป็นออยเลอร์ นี่คือการทดสอบที่สำหรับจำนวนเต็ม N ที่น่าจะเป็นไปได้ว่าเป็นประเภทเฉพาะหรือไม่และการทดสอบซ้ำ ๆ สามารถเพิ่มความน่าจะเป็นของความถูกต้องได้ ส่วนที่ช้าของการทดสอบนั้นส่วนใหญ่เกี่ยวข้องกับการคำนวณค่าที่คล้ายกับโมดูโล A ^ (N-1) N. ใครก็ตามที่ใช้การเข้ารหัสคีย์สาธารณะของ RSA ได้ใช้อัลกอริธึมนี้ มันมีประโยชน์ทั้งสำหรับจำนวนเต็มขนาดใหญ่ (เช่น 512 บิต) เช่นเดียวกับ 32 หรือ 64 บิตปกติ
การทดสอบสามารถเปลี่ยนจากการปฏิเสธความน่าจะเป็นการพิสูจน์แบบดั้งเดิมโดยการคำนวณพารามิเตอร์อินพุตการทดสอบบางอย่างซึ่งเป็นที่ทราบกันว่าประสบความสำเร็จสำหรับช่วงของ N แต่น่าเสียดายที่การค้นพบ "การทดสอบที่รู้จักกันดีที่สุด" เหล่านี้ ในความเป็นจริงไม่มีที่สิ้นสุด) โดเมน ในปี 1980 รายการแรกของการทดสอบที่มีประโยชน์ถูกสร้างขึ้นโดย Carl Pomerance (มีชื่อเสียงในการเป็นปัจจัยหนึ่งของ RSA-129 ด้วยอัลกอริทึม Seive Quadratic Seive ของเขา) ภายหลัง Jaeschke ปรับปรุงผลลัพธ์อย่างมีนัยสำคัญในปี 1993 ในปี 2004 จางและ Tang และข้อ จำกัด ของโดเมนการค้นหา Greathouse และ Livingstone ได้เปิดตัวผลการค้นหาที่ทันสมัยที่สุดจนถึงขณะนี้บนเว็บที่http://math.crg4.com/primes.htmlผลลัพธ์ที่ดีที่สุดของโดเมนการค้นหาขนาดใหญ่
ดูที่นี่สำหรับข้อมูลเพิ่มเติม: http://primes.utm.edu/prove/prove2_3.htmlและhttp://forums.nvidia.com/index.php?showtopic=70483
หากคุณต้องการวิธีในการสร้างจำนวนเฉพาะจำนวนมากและไม่สนใจที่จะสร้างหมายเลขเฉพาะทั้งหมด <จำนวนเต็ม n คุณสามารถใช้การทดสอบ Lucas-Lehmer เพื่อตรวจสอบหมายเลขเฉพาะของ Mersenne หมายเลขเฉพาะ Mersenne อยู่ในรูปแบบ 2 ^ p -1 ฉันคิดว่าการทดสอบ Lucas-Lehmer เป็นอัลกอริทึมที่เร็วที่สุดที่ค้นพบสำหรับหมายเลขเฉพาะของ Mersenne
และถ้าคุณไม่เพียง แต่ต้องการใช้อัลกอริธึมที่เร็วที่สุด แต่ยังเป็นฮาร์ดแวร์ที่เร็วที่สุดให้ลองติดตั้งโดยใช้ Nvidia CUDA เขียนเคอร์เนลสำหรับ CUDA และรันบน GPU
คุณสามารถหาเงินได้แม้หากคุณพบจำนวนเฉพาะจำนวนมากพอ EFF กำลังให้รางวัลตั้งแต่ $ 50K ถึง $ 250K: https://www.eff.org/awards/coop
มีการทดสอบทางคณิตศาสตร์ 100% ที่จะตรวจสอบว่ามีจำนวนเป็นP
เป็นสำคัญหรือคอมโพสิตเรียกว่าAKS Primality ทดสอบ
แนวคิดนั้นง่าย: ให้ตัวเลขP
ถ้าสัมประสิทธิ์(x-1)^P - (x^P-1)
ทั้งหมดหารด้วยP
แล้วP
ก็เป็นจำนวนเฉพาะมิฉะนั้นจะเป็นจำนวนประกอบ
ตัวอย่างเช่นที่กำหนดP = 3
จะให้พหุนาม:
(x-1)^3 - (x^3 - 1)
= x^3 + 3x^2 - 3x - 1 - (x^3 - 1)
= 3x^2 - 3x
และสัมประสิทธิ์นั้นหารด้วย3
ดังนั้นจำนวนจึงเป็นจำนวนเฉพาะ
และตัวอย่างที่P = 4
ซึ่งไม่ได้เป็นนายกจะให้:
(x-1)^4 - (x^4-1)
= x^4 - 4x^3 + 6x^2 - 4x + 1 - (x^4 - 1)
= -4x^3 + 6x^2 - 4x
และตรงนี้เราจะเห็นได้ว่าสัมประสิทธิ์6
ไม่หารด้วย4
ดังนั้นมันจึงไม่สำคัญ
พหุนาม(x-1)^P
จะเป็นP+1
คำและสามารถพบได้โดยใช้ชุดค่าผสม ดังนั้นการทดสอบนี้จะรันในO(n)
รันไทม์ดังนั้นฉันไม่รู้ว่าจะมีประโยชน์แค่ไหนเพราะคุณสามารถทำซ้ำได้i
ตั้งแต่ 0 ถึงp
และทดสอบส่วนที่เหลือ
x
ย่อหมายถึงอะไร? ใน(x-1)^P - (x^P-1)
. คุณมีรหัสตัวอย่างสำหรับสิ่งนี้หรือไม่? ใน C ++ สำหรับการพิจารณาว่าจำนวนเต็มหรือไม่?
เป็นปัญหาของคุณในการตัดสินใจว่าหมายเลขเฉพาะเป็นนายกหรือไม่ ถ้าอย่างนั้นคุณต้องมีการทดสอบเบื้องต้น (ง่าย) หรือคุณต้องการเวลาทั้งหมดถึงจำนวนที่กำหนด? ในกรณีที่ตัวกรองแบบนายกนั้นดี (ง่าย แต่ต้องการหน่วยความจำ) หรือคุณต้องการปัจจัยสำคัญของตัวเลข? สิ่งนี้จะต้องมีการแยกตัวประกอบ (ยากสำหรับคนจำนวนมากถ้าคุณต้องการวิธีที่มีประสิทธิภาพมากที่สุด) ตัวเลขที่คุณดูมีขนาดใหญ่แค่ไหน 16 บิต 32 บิต ใหญ่?
วิธีหนึ่งที่ชาญฉลาดและมีประสิทธิภาพคือการคำนวณตารางช่วงเวลาล่วงหน้าและเก็บไว้ในไฟล์โดยใช้การเข้ารหัสระดับบิต ไฟล์นั้นถือเป็นเวกเตอร์บิตยาวหนึ่งอันในขณะที่บิต n แทนเลขจำนวนเต็ม n ถ้า n เป็นไพรม์บิตจะถูกตั้งค่าเป็นหนึ่งและเป็นศูนย์มิฉะนั้น การค้นหารวดเร็วมาก (คุณคำนวณไบต์ออฟเซตและบิตมาสก์) และไม่ต้องการโหลดไฟล์ในหน่วยความจำ
Rabin-Millerเป็นการทดสอบความน่าจะเป็นแบบดั้งเดิม (คุณเรียกใช้เป็น K คูณและหมายเลขอินพุทอาจประกอบกันอย่างแน่นอนหรืออาจเป็นข้อผิดพลาดที่น่าจะเป็นข้อผิดพลาด 4 -K (ซ้ำสองสามร้อยครั้งและเกือบจะบอกความจริงกับคุณ)
มีที่ไม่น่าจะเป็น (กำหนด) เป็นตัวแปรของราบินมิลเลอร์
มหาราชอินเทอร์เน็ตเซนเนนายกค้นหา (Gimps) ซึ่งได้พบบันทึกของโลกสำหรับการพิสูจน์ที่สำคัญที่สุด (2 74207281 - 1 ณ มิถุนายน 2017) จะใช้ขั้นตอนวิธีการหลายแต่เหล่านี้เป็นจำนวนเฉพาะในรูปแบบพิเศษ อย่างไรก็ตามหน้า GIMPS ด้านบนไม่รวมการทดสอบเบื้องต้นแบบกำหนดแน่นอนทั่วไป ดูเหมือนว่าจะระบุว่าอัลกอริทึมใดที่ "เร็วที่สุด" ขึ้นอยู่กับขนาดของจำนวนที่จะทดสอบ หากหมายเลขของคุณพอดีกับ 64 บิตคุณอาจไม่ควรใช้วิธีที่มีเป้าหมายเพื่อกำหนดจำนวนหลักล้านหลายหลัก
ขึ้นอยู่กับใบสมัครของคุณ มีข้อควรพิจารณาบางอย่าง:
การทดสอบของ Miller-Rabin และอนาล็อกนั้นเร็วกว่าตะแกรงสำหรับตัวเลขที่มีขนาดที่แน่นอน ด้านล่างนั้นใช้แผนกทดลอง (ถ้าคุณมีตัวเลขไม่กี่ตัว) หรือตะแกรงจะเร็วกว่า
ฉันมักจะใช้วิธีนี้ในการคำนวณจำนวนเฉพาะตามด้วยอัลกอริทึมตะแกรง
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);
}
ฉันจะให้คุณตัดสินใจว่ามันเร็วที่สุดหรือไม่
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);
}
}
}
ใช้เวลาประมาณ 82 วินาทีในการค้นหาและพิมพ์ตัวเลขสำคัญในช่วง 1 ถึง 1,000,000 บนแล็ปท็อป Core 2 Duo ของฉันพร้อมโปรเซสเซอร์ 2.40 GHz และพบว่ามีจำนวนเฉพาะ78,498ตัว
i <= (ToCheck / 3)
ปัญหาคือ i <= (ToCheck / i)
มันควรจะเป็น ด้วยมันอาจทำงานใน 0.1 วินาทีแทน
#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);
}
ฉันไม่รู้เกี่ยวกับอัลกอริทึมที่กำหนดไว้ล่วงหน้า แต่ฉันสร้างของตัวเองซึ่งเร็วมาก สามารถประมวลผลตัวเลข 20 หลักในเวลาน้อยกว่า 1 วินาที ความสามารถสูงสุดของโปรแกรมนี้คือ 18446744073709551615 โปรแกรมคือ:
#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)
เป็นสิ่งที่ดีแม้ว่า :)
ฉันรู้ว่ามันค่อนข้างช้า แต่สิ่งนี้มีประโยชน์สำหรับผู้ที่มาที่นี่จากการค้นหา อย่างไรก็ตามนี่คือ JavaScript บางส่วนที่ต้องอาศัยความจริงที่ว่าจะต้องมีการทดสอบเฉพาะปัจจัยสำคัญเท่านั้นดังนั้นค่า primes ก่อนหน้านี้ที่สร้างโดยรหัสนั้นจะถูกใช้อีกครั้งเพื่อใช้เป็นปัจจัยทดสอบในภายหลัง แน่นอนว่าค่าทั้งหมดและ mod 5 จะถูกกรองออกก่อน ผลลัพธ์จะอยู่ในอาร์เรย์ P และรหัสนี้สามารถกระทืบ 10 ล้านครั้งภายในเวลา 1.5 วินาทีบน i7 พีซี (หรือ 100 ล้านในประมาณ 20) เขียนใหม่ใน C ควรเร็วมาก
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;
ก็จะช้าลง O (N ^ 2) แต่นั่นอาจถูกมองว่าเป็นข้อผิดพลาดในการเขียนโค้ดอยู่แล้ว การบันทึกและทดสอบตามช่วงเวลาคือ O (N ^ 2 / (บันทึก N) ^ 2) และการทดสอบตามช่วงเวลาด้านล่างสแควร์รูทของตัวเลขเท่านั้นคือ O (N ^ 1.5 / (บันทึก N) ^ 2)