C ++를 사용하여 소수를 찾는 가장 빠른 알고리즘은 무엇입니까? 나는 체의 알고리즘을 사용했지만 여전히 더 빠르기를 원합니다!
C ++를 사용하여 소수를 찾는 가장 빠른 알고리즘은 무엇입니까? 나는 체의 알고리즘을 사용했지만 여전히 더 빠르기를 원합니다!
답변:
Atkin 의 체를 매우 빠르게 구현 한 것은 Dan Bernstein의 primgen 입니다. 이 체는 에라토스테네스 의 체 보다 더 효율적 입니다. 그의 페이지에는 몇 가지 벤치 마크 정보가 있습니다.
정말 빠르면 프라임 목록을 포함시킬 수 있습니다 :
http://www.bigprimes.net/archive/prime/
특정 숫자가 소수인지 알아야 할 경우 wikipedia에 다양한 소수 테스트가 나열됩니다 . 그들은 숫자 인 경우 그들이 당신을 말할 수있는, 특히 있기 때문에, 아마도 많은 수의 소수 있는지 확인하는 가장 빠른 방법입니다 하지 주요.
그는 내가 오래된 질문에 대답하는 질문 necromancer라는 것을 알고 있지만, 효율적인 소수 테스트를 구현하는 방법을 찾기 위해이 질문을 검색했습니다.
지금까지 가장 빠른 소수 테스트 알고리즘은 SPRP (강한 확률 프라임)라고 생각합니다. Nvidia CUDA 포럼에서 인용하고 있습니다.
수 이론에서보다 실질적인 틈새 문제 중 하나는 소수를 식별하는 것과 관련이 있습니다. N이 주어지면 그것이 소수인지 어떻게 효율적으로 결정할 수 있습니까? 이것은 단순한 문제가 아니라 특정 범위 내에서 주요 해시 테이블 크기를 동적으로 찾아야 할 때 코드에서 실제로 필요한 것일 수 있습니다. N이 2 ^ 30 정도 인 경우 실제로 요인을 찾기 위해 30000 나누기 테스트를 수행 하시겠습니까? 당연히 아니.
이 문제에 대한 일반적인 실용적인 해결책은 Euler 가능성있는 소수 테스트라고하는 간단한 테스트와 SPRP (강한 가능성있는 소수)라고하는보다 강력한 일반화입니다. 이것은 정수 N에 대해 확률 적으로이를 소수로 분류 할 수 있고 반복 된 테스트로 정확성 확률을 높일 수있는 테스트입니다. 테스트 자체의 느린 부분은 대부분 A ^ (N-1) modulo N과 비슷한 값을 계산하는 것입니다. RSA 공개 키 암호화 변형을 구현하는 사람은이 알고리즘을 사용했습니다. 512 비트와 같은 큰 정수와 일반 32 또는 64 비트 정수 모두에 유용합니다.
N 범위에 대해 항상 성공하는 것으로 알려진 특정 테스트 입력 매개 변수를 사전 계산하여 확률 적 거부에서 우선 순위의 확실한 증거로 테스트를 변경할 수 있습니다. 불행히도 이러한 "최고의 테스트"를 발견하는 것은 사실상 실제로 무한) 도메인. 1980 년 Carl Pomerance가 유용한 테스트의 첫 번째 목록을 작성했습니다 (이차적 시브 알고리즘으로 RSA-129를 인수하는 것으로 유명). 나중에 Jaeschke는 1993 년에 결과를 크게 개선했습니다. 2004 년에 Zhang과 Tang은 이론을 개선했습니다. 그리고 검색 도메인의 한계. Greathouse and 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 소수를 확인할 수 있습니다. 메르 센 소수는 2 ^ p -1 형식입니다. 나는 Lucas-Lehmer 테스트가 Mersenne 소수에서 발견 된 가장 빠른 알고리즘이라고 생각합니다.
또한 가장 빠른 알고리즘뿐만 아니라 가장 빠른 하드웨어를 사용하려면 Nvidia CUDA를 사용하여 구현하고 CUDA 용 커널을 작성한 후 GPU에서 실행하십시오.
충분히 큰 소수를 발견하면 돈을 벌 수 있습니다. EFF는 $ 50K에서 $ 250K까지 상금을 제공합니다. https://www.eff.org/awards/coop
AKS Primality TestP
라는 숫자 가 소수인지 또는 복합 인지를 확인하는 100 % 수학 테스트가 있습니다.
개념은 간단하다 : 숫자 주어진 P
모든 계수는 경우 (x-1)^P - (x^P-1)
로 나눌 수 있습니다 P
, 다음 P
소수이고, 그렇지 않으면 복합 숫자입니다.
예를 들어 given 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이 소수이면 비트는 1로 설정되고 그렇지 않으면 0으로 설정됩니다. 조회가 매우 빠르며 (바이트 오프셋과 비트 마스크를 계산) 파일을 메모리에로드 할 필요가 없습니다.
Rabin-Miller 는 표준 확률 적 우선 성 테스트입니다. (K 번 실행하고 입력 번호는 확실히 복합적이거나 아마도 오류 4 -K 확률로 소수입니다 . (수백 번 반복되며 거의 확실하게 진실을 알려줍니다))
Rabin Miller 의 비 확률 적 (결정 론적) 변형이 있습니다.
큰 인터넷 메르 센 국무 검색 최대 규모의 검증 된 소수의 세계 기록을 발견했다 (원기 충전) (2 74207281 - 6 월 2017로 1) 사용 여러 가지 알고리즘을 하지만, 이러한 특별한 형태의 소수입니다. 그러나 위의 GIMPS 페이지에는 일반적인 결정 론적 우선 순위 테스트가 포함되어 있습니다. 어떤 알고리즘이 "가장 빠른"알고리즘인지는 테스트 할 숫자의 크기에 달려 있음을 나타냅니다. 숫자가 64 비트에 맞으면 아마도 수백만 자릿수의 소수 자릿수에서 작동하는 방법을 사용해서는 안됩니다.
나는 항상이 방법을 사용하여 체 알고리즘을 따르는 소수를 계산합니다.
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);
}
}
}
2.40GHz 프로세서가 장착 된 Core 2 Duo 랩톱에서 1에서 1,000,000 사이의 소수를 찾아 인쇄하는 데 약 82 초가 걸립니다 . 그리고 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);
}
사전 정의 된 알고리즘에 대해 모르지만 매우 빠른 자체 알고리즘을 만들었습니다. 1 초 이내에 20 자리 숫자를 처리 할 수 있습니다. 이 프로그램의 최대 기능은 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가 있습니다. 따라서 코드에서 생성 된 초기 소수는 이후 요소의 테스트 요소로 재사용됩니다. 물론 모든 짝수 및 mod 5 값이 먼저 필터링됩니다. 결과는 배열 P에있을 것이며,이 코드는 i7 PC에서 1.5 초 이내에 1000 만 프라임 (또는 약 20 만에서 1 억)을 처리 할 수 있습니다. 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 / (log N) ^ 2)이고, 소수의 제곱근 이하의 소수에 의한 테스트는 O (N ^ 1.5 / (log N) ^ 2)입니다.