Thuật toán nhanh nhất để tìm ra số nguyên tố sử dụng C ++ là gì? Tôi đã sử dụng thuật toán sàng nhưng tôi vẫn muốn nó nhanh hơn!
Thuật toán nhanh nhất để tìm ra số nguyên tố sử dụng C ++ là gì? Tôi đã sử dụng thuật toán sàng nhưng tôi vẫn muốn nó nhanh hơn!
Câu trả lời:
Một thực hiện rất nhanh trong những Sàng Atkin là Dan Bernstein primegen . Sàng này hiệu quả hơn Sàng của Eratosthenes . Trang của anh ấy có một số thông tin điểm chuẩn.
Nếu nó phải thực sự nhanh, bạn có thể bao gồm một danh sách các số nguyên tố:
http://www.bigprimes.net/archive/prime/
Nếu bạn chỉ cần biết nếu một số nhất định là số nguyên tố, có nhiều bài kiểm tra nguyên tố khác nhau được liệt kê trên wikipedia . Chúng có lẽ là phương pháp nhanh nhất để xác định xem số lớn có phải là số nguyên tố hay không, đặc biệt là vì chúng có thể cho bạn biết nếu một số không phải là số nguyên tố.
Anh ấy, anh ấy tôi biết tôi là một câu hỏi cần thiết trả lời các câu hỏi cũ, nhưng tôi vừa tìm thấy câu hỏi này để tìm kiếm các cách để thực hiện các bài kiểm tra số nguyên tố hiệu quả.
Cho đến bây giờ, tôi tin rằng thuật toán kiểm tra số nguyên tố nhanh nhất là Strong Probable Prime (SPRP). Tôi đang trích dẫn từ các diễn đàn NDA của CUDA:
Một trong những vấn đề thực tế hơn trong lý thuyết số có liên quan đến việc xác định các số nguyên tố. Cho N, làm thế nào bạn có thể xác định một cách hiệu quả nếu nó là số nguyên tố hay không? Đây không chỉ là một vấn đề mang tính lý thuyết, nó có thể là một vấn đề thực sự cần thiết trong mã, có lẽ khi bạn cần tự động tìm kích thước bảng băm chính trong phạm vi nhất định. Nếu N là thứ gì đó theo thứ tự 2 ^ 30, bạn có thực sự muốn thực hiện 30000 bài kiểm tra phân chia để tìm kiếm bất kỳ yếu tố nào không? Rõ ràng là không.
Giải pháp thực tế phổ biến cho vấn đề này là một thử nghiệm đơn giản gọi là thử nghiệm nguyên tố có thể xảy ra của Euler và một khái quát mạnh mẽ hơn được gọi là Prime Prime có thể mạnh mẽ (SPRP). Đây là một thử nghiệm mà đối với một số nguyên N có thể phân loại chính xác nó là số nguyên tố hay không, và các thử nghiệm lặp lại có thể làm tăng xác suất chính xác. Phần chậm của bản thân bài kiểm tra chủ yếu liên quan đến việc tính toán một giá trị tương tự như modulo A ^ (N-1) N. Bất kỳ ai thực hiện các biến thể mã hóa khóa công khai RSA đều sử dụng thuật toán này. Nó hữu ích cho cả số nguyên lớn (như 512 bit) cũng như ints 32 hoặc 64 bit thông thường.
Thử nghiệm có thể được thay đổi từ một từ chối xác suất thành một bằng chứng xác thực về tính nguyên thủy bằng cách tính toán trước các tham số đầu vào thử nghiệm được biết là luôn thành công trong phạm vi của N. Thật không may, việc phát hiện ra các "thử nghiệm nổi tiếng nhất" này thực sự là một tìm kiếm rất lớn ( trong thực tế vô hạn) miền. Vào năm 1980, một danh sách các thử nghiệm hữu ích đầu tiên đã được Carl Pomerance tạo ra (nổi tiếng là nhân tố RSA-129 với thuật toán Quadratic Seive của ông.) Sau đó Jaeschke đã cải thiện kết quả đáng kể vào năm 1993. Năm 2004, Zhang và Tang đã cải thiện lý thuyết và giới hạn của miền tìm kiếm. Greathouse và Livingstone đã phát hành các kết quả hiện đại nhất cho đến bây giờ trên web, tại http://math.crg4.com/primes.html , kết quả tốt nhất của một miền tìm kiếm khổng lồ.
Xem tại đây để biết thêm: http://primes.utm.edu/prove/prove2_3.html và http://forums.nvidia.com/index.php?showtopic=70483
Nếu bạn chỉ cần một cách để tạo các số nguyên tố rất lớn và không quan tâm đến việc tạo tất cả các số nguyên tố <một số nguyên n, bạn có thể sử dụng phép thử Lucas-Lehmer để xác minh các số nguyên tố Mersenne. Một số nguyên tố Mersenne có dạng 2 ^ p -1. Tôi nghĩ rằng bài kiểm tra Lucas-Lehmer là thuật toán nhanh nhất được phát hiện cho các số nguyên tố Mersenne.
Và nếu bạn không chỉ muốn sử dụng thuật toán nhanh nhất mà còn cả phần cứng nhanh nhất, hãy thử triển khai nó bằng Nvidia CUDA, viết kernel cho CUDA và chạy nó trên GPU.
Bạn thậm chí có thể kiếm được một số tiền nếu bạn phát hiện ra số nguyên tố đủ lớn, EFF đang trao giải thưởng từ $ 50K đến $ 250K: https://www.eff.org/awards/coop
Có một bài kiểm tra toán học 100% sẽ kiểm tra xem một số P
là số nguyên tố hay tổng hợp, được gọi là Kiểm tra tính nguyên thủy của AKS .
Khái niệm này rất đơn giản: cho một số P
, nếu tất cả các hệ số (x-1)^P - (x^P-1)
chia hết cho P
, thì đó P
là một số nguyên tố, nếu không nó là một số tổng hợp.
Chẳng hạn, đã cho P = 3
, sẽ đưa ra đa thức:
(x-1)^3 - (x^3 - 1)
= x^3 + 3x^2 - 3x - 1 - (x^3 - 1)
= 3x^2 - 3x
Và các hệ số đều chia hết cho nhau 3
, do đó số là số nguyên tố.
Và ví dụ, nơi P = 4
KHÔNG phải là số nguyên tố sẽ mang lại:
(x-1)^4 - (x^4-1)
= x^4 - 4x^3 + 6x^2 - 4x + 1 - (x^4 - 1)
= -4x^3 + 6x^2 - 4x
Và ở đây chúng ta có thể thấy rằng các hệ số 6
không chia hết cho4
, do đó nó KHÔNG phải là số nguyên tố.
Đa thức (x-1)^P
sẽ P+1
điều khoản và có thể được tìm thấy bằng cách sử dụng kết hợp. Vì vậy, bài kiểm tra này sẽ chạy trong O(n)
thời gian chạy, vì vậy tôi không biết điều này sẽ hữu ích như thế nào vì bạn chỉ có thể lặp lại i
từ 0 đến p
và kiểm tra phần còn lại.
x
viết tắt của từ gì? trong (x-1)^P - (x^P-1)
. Bạn có một mã mẫu cho việc này? trong C ++ để xác định xem số nguyên có phải là số nguyên tố hay không?
Là vấn đề của bạn để quyết định xem một số cụ thể là số nguyên tố? Sau đó, bạn cần một bài kiểm tra nguyên thủy (dễ dàng). Hay bạn cần tất cả các số nguyên tố lên đến một số đã cho? Trong trường hợp đó, sàng nguyên tố là tốt (dễ, nhưng đòi hỏi bộ nhớ). Hay bạn cần các yếu tố chính của một số? Điều này sẽ đòi hỏi yếu tố hóa (khó khăn cho số lượng lớn nếu bạn thực sự muốn các phương pháp hiệu quả nhất). Làm thế nào lớn là những con số bạn đang nhìn? 16 bit? 32 bit? to hơn?
Một cách thông minh và hiệu quả là tính toán trước các bảng số nguyên tố và giữ chúng trong một tệp bằng cách sử dụng mã hóa mức bit. Tệp được coi là một vectơ bit dài trong khi bit n đại diện cho số nguyên n. Nếu n là số nguyên tố, bit của nó được đặt thành một và bằng không nếu không. Tra cứu rất nhanh (bạn tính toán bù byte và mặt nạ bit) và không yêu cầu tải tệp trong bộ nhớ.
Rabin-Miller là một thử nghiệm nguyên thủy xác suất tiêu chuẩn. (bạn chạy nó K lần và số đầu vào chắc chắn là tổng hợp hoặc có thể là nguyên nhân có xác suất xảy ra lỗi 4 -K . (vài trăm lần lặp và nó gần như chắc chắn cho bạn biết sự thật)
Có một biến thể không xác suất (xác định) của Rabin Miller .
Các vĩ đại Internet Mersenne Thủ Search (GIMPS) đã tìm thấy kỷ lục thế giới cho nguyên tố lớn nhất đã được chứng minh (2 74.207.281 - 1 tháng Sáu 2017), sử dụng một số thuật toán , nhưng đây là những số nguyên tố trong các hình thức đặc biệt. Tuy nhiên, trang GIMPS ở trên không bao gồm một số thử nghiệm nguyên thủy xác định chung. Chúng xuất hiện để chỉ ra rằng thuật toán nào là "nhanh nhất" phụ thuộc vào kích thước của số được kiểm tra. Nếu số của bạn vừa với 64 bit thì có lẽ bạn không nên sử dụng một phương pháp dự định hoạt động trên các số nguyên tố vài triệu chữ số.
Nó phụ thuộc vào ứng dụng của bạn. Có một số cân nhắc:
Các thử nghiệm Miller-Rabin và tương tự chỉ nhanh hơn một cái sàng cho các con số trên một kích thước nhất định (tôi tin rằng khoảng vài triệu). Dưới mức đó, sử dụng một bộ phận dùng thử (nếu bạn chỉ có một vài số) hoặc một cái sàng sẽ nhanh hơn.
Tôi luôn sử dụng phương pháp này để tính các số nguyên tố theo thuật toán sàng.
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);
}
Tôi sẽ để bạn quyết định xem nó có nhanh nhất hay không.
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);
}
}
}
Mất khoảng 82 giây để tìm và in các số nguyên tố trong phạm vi từ 1 đến 1.000.000, trên máy tính xách tay Core 2 Duo của tôi với bộ xử lý 2,40 GHz. Và nó đã tìm thấy 78.498 số nguyên tố.
i <= (ToCheck / 3)
. nó phải được i <= (ToCheck / i)
. với nó, nó có thể chạy trong 0,1 giây thay thế.
#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);
}
Tôi không biết về bất kỳ thuật toán được xác định trước nào nhưng tôi đã tạo ra thuật toán của riêng mình rất nhanh. Nó có thể xử lý 20 chữ số trong chưa đầy 1 giây. Khả năng tối đa của chương trình này là 18446744073709551615. Chương trình này là:
#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)
là loại tốt mặc dù. :)
Tôi biết điều đó muộn hơn một chút, nhưng điều này có thể hữu ích cho những người đến đây từ các tìm kiếm. Dù sao, đây là một số JavaScript dựa trên thực tế là chỉ cần kiểm tra các yếu tố chính, do đó, các số nguyên tố trước đó được tạo bởi mã được sử dụng lại làm yếu tố kiểm tra cho các yếu tố sau. Tất nhiên, tất cả các giá trị chẵn và mod 5 được lọc ra trước tiên. Kết quả sẽ nằm trong mảng P và mã này có thể tạo ra 10 triệu số nguyên tố trong vòng dưới 1,5 giây trên PC i7 (hoặc 100 triệu trong khoảng 20). Viết lại bằng C nên rất nhanh.
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;
nó thậm chí còn chậm hơn, O (N ^ 2), nhưng đó có thể được coi là một lỗi mã hóa. lưu và kiểm tra theo các số nguyên tố là O (N ^ 2 / (log N) ^ 2) và kiểm tra theo các số nguyên tố chỉ dưới căn bậc hai của số, là O (N ^ 1.5 / (log N) ^ 2).