Какой самый быстрый алгоритм для определения простых чисел с помощью C ++? Я использовал алгоритм сита, но все еще хочу, чтобы он был быстрее!
Какой самый быстрый алгоритм для определения простых чисел с помощью C ++? Я использовал алгоритм сита, но все еще хочу, чтобы он был быстрее!
Ответы:
Очень быстрое внедрение « Сита Аткина» - праймэн Дана Бернштейна . Это сито более эффективно, чем сито Эратосфена . Его страница содержит некоторую информацию о тестах.
Если это должно быть очень быстро, вы можете включить список простых чисел:
http://www.bigprimes.net/archive/prime/
Если вам просто нужно знать, является ли определенное число простым числом, в википедии перечислены различные простые тесты . Они, вероятно , самый быстрый способ , чтобы определить , если большие числа простых чисел, особенно потому , что они могут сказать вам , если число не простое.
Он, он, я знаю, что я некромант, отвечающий на старые вопросы, но я только что нашел этот вопрос, ища в сети способы реализации эффективных тестов простых чисел.
До сих пор я считаю, что самый быстрый алгоритм тестирования простых чисел - это Strong Probable Prime (SPRP). Я цитирую форумы Nvidia CUDA:
Одна из наиболее практичных проблем ниши в теории чисел связана с идентификацией простых чисел. Учитывая N, как вы можете эффективно определить, является ли оно простым или нет? Это не просто теоретическая проблема, это может быть реальная проблема, необходимая в коде, возможно, когда вам нужно динамически найти размер основной хеш-таблицы в определенных диапазонах. Если N что-то порядка 2 ^ 30, вы действительно хотите провести 30000 тестов с делением, чтобы найти какие-либо факторы? Очевидно нет.
Общепринятое практическое решение этой проблемы - это простой тест, называемый тестом вероятного простого числа Эйлера, и более мощное обобщение, называемое сильным вероятным простым числом (SPRP). Это тест, который для целого числа N может вероятностно классифицировать его как простое или нет, а повторные тесты могут увеличить вероятность правильности. Медленная часть самого теста в основном включает вычисление значения, аналогичного A ^ (N-1) по модулю N. Любой, кто реализует варианты шифрования с открытым ключом RSA, использовал этот алгоритм. Это полезно как для больших целых чисел (например, 512 бит), так и для обычных 32 или 64 битных целых.
Тест может быть изменен с вероятностного отклонения на окончательное доказательство первичности путем предварительного вычисления определенных входных параметров теста, которые, как известно, всегда успешны для диапазонов N. К сожалению, обнаружение этих «самых известных тестов» фактически является поиском огромного ( фактически бесконечный) домен. В 1980 году Карл Померанс (Carl Pomerance) создал первый список полезных тестов (известный тем, что он вычисляет RSA-129 с помощью алгоритма Quadratic Seive). Позднее Йешке значительно улучшил результаты в 1993 году. В 2004 году Чжан и Тан улучшили теорию и пределы поискового домена. 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, вы можете использовать тест Лукаса-Лемера для проверки простых чисел Мерсенна. Простое число Мерсенна имеет вид 2 ^ p -1. Я думаю, что тест Лукаса-Лемера - самый быстрый алгоритм, открытый для простых чисел Мерсенна.
И если вы хотите использовать не только самый быстрый алгоритм, но и самое быстрое оборудование, попробуйте реализовать его с помощью Nvidia CUDA, написать ядро для CUDA и запустить его на GPU.
Вы даже можете заработать немного денег, если обнаружите достаточно большие простые числа, EFF раздает призы от $ 50K до $ 250K: https://www.eff.org/awards/coop
Существует 100% математический тест, который проверяет, является ли число P
простым или составным, называется AKS Primality Test .
Концепция проста: при заданном числе 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 простое, его бит устанавливается в единицу и в противном случае равен нулю. Поиск очень быстрый (вы вычисляете смещение байта и битовую маску) и не требует загрузки файла в память.
Рабин-Миллер является стандартным вероятностным тестом простоты. (вы запускаете его K раз, и входное число либо однозначно составное, либо, вероятно, оно простое с вероятностью ошибки 4 -K . (несколько сотен итераций, и почти наверняка это говорит вам правду)
Существует не вероятностный (детерминистский) вариант Рабина Миллера .
Great Internet Mersenne Prime Search (GIMPS) , который нашел мировой рекорд по величине доказанным штрихом (2 74,207,281 - 1 по состоянию на июнь 2017 года), использует несколько алгоритмов , но это простые числа в специальных формах. Однако приведенная выше страница GIMPS включает в себя некоторые общие детерминированные тесты первичности. Похоже, они указывают на то, что алгоритм является «самым быстрым», зависит от размера проверяемого числа. Если ваше число соответствует 64 битам, то вам, вероятно, не следует использовать метод, предназначенный для работы с простыми числами из нескольких миллионов цифр.
Это зависит от вашего приложения. Есть несколько соображений:
Тесты Миллера-Рабина и аналоговые тесты выполняются только быстрее, чем сито для чисел более определенного размера (я полагаю, где-то около нескольких миллионов). Ниже, используя пробное деление (если у вас есть только несколько чисел) или сито быстрее.
Я дам вам решить, будет ли это быстрее или нет.
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);
}
}
}
На моем ноутбуке Core 2 Duo с процессором 2,40 ГГц процесс поиска и печати простых чисел в диапазоне от 1 до 1 000 000 занимает около 82 секунд . И найдено 78 498 простых чисел.
i <= (ToCheck / 3)
. так и должно быть i <= (ToCheck / i)
. с этим, это могло бы бежать через 0,1 секунды вместо этого.
Я всегда использую этот метод для вычисления чисел простых чисел, следующих за алгоритмом сита.
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);
}
Я не знаю ни одного предопределенного алгоритма, но я создал свой собственный, который очень быстрый. Он может обрабатывать 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, который основывается на том факте, что нужно проверять только простые факторы, поэтому более ранние простые числа, сгенерированные кодом, повторно используются в качестве тестовых факторов для более поздних. Конечно, все четные значения и значения mod 5 отфильтровываются первыми. Результат будет в массиве P, и этот код может обработать 10 миллионов простых чисел менее чем за 1,5 секунды на ПК i7 (или 100 миллионов примерно за 20). Переписано на С это должно быть очень быстро.
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).