Какой самый быстрый алгоритм для нахождения простых чисел?

Какой самый быстрый алгоритм для поиска простых чисел с помощью С++? Я использовал ситовый алгоритм, но я все еще хочу, чтобы он был быстрее!

Ответ 1

Очень быстрая реализация Сито Аткина - Дан Бернштейн primegen. Это сито более эффективно, чем Сито Эратосфена. Его страница имеет некоторую контрольную информацию.

Ответ 2

Если он должен быть действительно быстрым, вы можете включить список простых чисел:
http://www.bigprimes.net/archive/prime/

Если вам просто нужно знать, является ли определенное число простым числом, существуют различные основные тесты, перечисленные в wikipedia. Вероятно, это самый быстрый способ определить, являются ли большие числа штрихами, особенно потому, что они могут сказать вам, что число не является простым.

Ответ 3

Он, он я знаю, что я некромант вопроса, отвечающий на старые вопросы, но я только что нашел этот вопрос, ищущий сеть для способов эффективного тестирования простых чисел.

До сих пор я считаю, что самым быстрым алгоритмом тестирования простых чисел является Strong Probable Prime (SPRP). Я цитирую форумы Nvidia CUDA:

Одна из наиболее практических нишевых проблем в теории чисел должна делать с идентификацией простых чисел. Учитывая N, как вы можете эффективно определить, является ли оно простым или нет? Это не просто теоретический проблема, она может быть реальной, необходимой в коде, возможно, когда вам нужно динамически находить основной размер хэш-таблицы в определенных диапазонах. Если N что-то порядка 2 ^ 30, вы действительно хотите сделать 30000 деление тесты для поиска каких-либо факторов? Очевидно, что нет.

Общим практическим решением этой проблемы является простой тест, называемый вероятный простой тест Эйлера и более мощное обобщение называемый Сильно вероятный премьер (SPRP). Это тест, который целое число N может вероятностно классифицировать его как простое или нет, и повторные тесты могут увеличить вероятность правильности. Медленная часть самого теста в основном включает вычисление значения, аналогичного A ^ (N-1) по модулю N. Любой, кто реализует шифрование с открытым ключом RSA варианты использовали этот алгоритм. Он полезен как для огромных целых чисел (например, 512 бит), а также нормальные 32 или 64-битные ints.

Тест может быть изменен с вероятностного отклонения на окончательное доказательство примитивности путем предвычисления определенного тестового ввода параметры, которые, как известно, всегда преуспевают для диапазонов N. К сожалению, открытие этих "наиболее известных тестов" эффективно поиск огромного (фактически бесконечного) домена. В 1980 году первый список полезные тесты были созданы Карлом Померансом (известный как один фактор RSA-129 с его алгоритмом Quadratic Seive.) Позже Jaeschke значительно улучшили результаты в 1993 году. В 2004 году Чжан и Тан улучшили теорию и пределы области поиска. Greathouse и Ливингстон опубликовал самые современные результаты до сих пор на в Интернете, 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 для проверки простых чисел Мерсена. Простое число Мерсенна имеет вид 2 ^ р-1. Я думаю, что тест Lucas-Lehmer - это самый быстрый алгоритм, обнаруженный для простых чисел Мерсенна.

И если вы не только хотите использовать самый быстрый алгоритм, но и самое быстрое аппаратное обеспечение, попробуйте реализовать его с помощью Nvidia CUDA, напишите ядро ​​для CUDA и запустите его на GPU.

Вы даже можете заработать немного денег, если обнаружите достаточно большие простые числа, EFF дает призы от $50K до $250K: https://www.eff.org/awards/coop

Ответ 4

Существует 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 и проверить оставшуюся часть.

Ответ 5

Является ли ваша проблема решить, является ли конкретное число простым? Тогда вам нужен тест на примитивность (легко). Или вам нужны все простые числа до определенного номера? В этом случае простые сита хороши (легкие, но требуют памяти). Или вам нужны основные коэффициенты числа? Это потребует факторизации (для больших чисел это сложно, если вы действительно хотите использовать наиболее эффективные методы). Насколько велики числа, на которые вы смотрите? 16 бит? 32 бит? больше?

Один умный и эффективный способ - предварительно вычислить таблицы простых чисел и сохранить их в файле с использованием кодирования на уровне бит. Файл считается одним длинным битовым вектором, тогда как бит n представляет целое число n. Если n является простым, его бит устанавливается равным единице и равен нулю в противном случае. Поиск очень быстрый (вы вычисляете смещение байта и бит-маску) и не требует загрузки файла в память.

Ответ 6

Rabin-Miller является стандартным вероятностным критерием примитивности. (вы запускаете его K раз, а номер ввода либо определенно композитный, либо он, вероятно, является простым с вероятностью ошибки 4 -K (несколько сот итераций и это почти наверняка говорит вам правду)

Существует невариантный (детерминированный) вариант Отличный интернет-поиск Mersenne Prime Search (GIMPS), который нашел мировой рекорд для большинства проверенных простых (2 74,207,281 - 1 по состоянию на июнь 2017 года), использует несколько алгоритмов, но это простые числа в специальных формах. Однако на странице GIMPS выше приведены некоторые общие детерминированные тесты примитивности. Похоже, они указывают, что алгоритм "самый быстрый" зависит от размера проверяемого числа. Если ваш номер соответствует 64 битам, вы, вероятно, не должны использовать метод, предназначенный для работы с числами в несколько миллионов цифр.

Ответ 7

Это зависит от вашего приложения. Есть несколько соображений:

  • Вам нужна только информация о том, являются ли несколько чисел первичными, вам нужны все простые числа до определенного предела или вам (потенциально) все простые числа?
  • Насколько велики числа, с которыми вам приходится иметь дело?

Миллер-Рабин и аналоговые тесты выполняются быстрее, чем сито для чисел с определенным размером (где-то около нескольких миллионов, я считаю). Ниже, используя пробное деление (если у вас только несколько чисел) или сито быстрее.

Ответ 8

Я позволю вам решить, будет ли это быстрее или нет.

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 ГГц. И он нашел 78 498 простых чисел.

Ответ 9

Я всегда использую этот метод для вычисления чисел простых чисел, следующих с алгоритмом решета.

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);
 }

Ответ 10

Я не знаю ни одного предопределенного алгоритма, но я создал свой собственный, который очень быстрый. Он может обрабатывать 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;
}

Ответ 11

#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);
}    

Ответ 12

#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;
}

Ответ 13

Я знаю это несколько позже, но это может быть полезно людям, прибывающим сюда из поисков. Во всяком случае, здесь есть JavaScript, основанный на том, что нужно тестировать только простые факторы, поэтому более ранние простые числа, генерируемые кодом, повторно используются в качестве тестовых факторов для более поздних. Конечно, все четные и 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
}

Ответ 14

#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<<", ";

    }
}