Який найшвидший алгоритм для пошуку простих чисел за допомогою C ++? Я використовував алгоритм сита, але все одно хочу, щоб це було швидше!
Який найшвидший алгоритм для пошуку простих чисел за допомогою C ++? Я використовував алгоритм сита, але все одно хочу, щоб це було швидше!
Відповіді:
Дуже швидке втілення Сита Аткіна - першоджерело Дана Бернштейна . Це сито є більш ефективним, ніж сито Ератостена . На його сторінці є деяка орієнтирна інформація.
Якщо це має бути дуже швидким, ви можете включити список простих чисел:
http://www.bigprimes.net/archive/prime/
Якщо ви просто повинні знати, чи є певне число простим числом, у Вікіпедії є різні прості тести . Вони, мабуть, найшвидший метод визначити, чи велика кількість є простими числами, тим більше, що вони можуть сказати вам, якщо число не є простим.
Він, він, я знаю, я некромант, який відповідає на старі запитання, але я щойно знайшов це запитання в мережі, щоб знайти шляхи для ефективного тестування простих чисел.
Досі я вважаю, що найшвидший алгоритм тестування простих чисел - це сильний ймовірний прайм (SPRP). Я цитую з форумів Nvidia CUDA:
Одна з найбільш практичних нішевих проблем теорії чисел пов'язана з ідентифікацією простих чисел. З огляду на N, як можна ефективно визначити, чи це простий чи ні? Це не просто проблема з тіеретичною проблемою, це може бути справжня потреба в коді, можливо, коли вам потрібно динамічно знаходити основний розмір хеш-таблиці в певних діапазонах. Якщо N - це щось порядком 2 ^ 30, чи дійсно ви хочете зробити 30000 тестів поділу для пошуку будь-яких факторів? Очевидно, що ні.
Поширеним практичним рішенням цієї проблеми є простий тест, який називається ймовірним простим тестом Ейлера, і більш потужне узагальнення, яке називається сильним ймовірним простим рівнем (SPRP). Це тест, який для цілого N може імовірнісно класифікувати його як простий чи ні, а повторні тести можуть збільшити ймовірність правильності. Сама повільна частина тесту включає в себе обчислення значення, схожого на A ^ (N-1) модуль N. Кожен, хто реалізує варіанти шифрування відкритого ключа RSA, використовував цей алгоритм. Це корисно як для величезних цілих чисел (наприклад, 512 біт), так і для звичайних 32 або 64 бітових ints.
Тест можна змінити від імовірнісного відхилення до остаточного доказу первинності, попередньо обчисливши певні вхідні параметри тесту, які, як відомо, завжди вдається для діапазонів N. На жаль, виявлення цих "найвідоміших тестів" є результатом пошуку величезного ( насправді нескінченний) домен. У 1980 р. Був створений перший список корисних тестів Карлом Померансом (відомим тим, що був фактор RSA-129 за допомогою його квадратичного алгоритму Seive.) Пізніше Jaeschke значно покращив результати в 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 дає призи від 50 000 до 250 000 доларів: 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- К . (кілька сотень ітерацій, і це майже напевно говорить вам правду)
Існує неімовірнісний (детермінований) варіант Рабіна Міллера .
Great Internet Mersenne Prime Search (GIMPS) , який знайшов світовий рекорд за величиною доведеним штрихом (2 74,207,281 - 1 станом на червень 2017 року), використовує кілька алгоритмів , але це прості числа в спеціальних формах. Однак на сторінці 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);
}
}
}
На пошуку мого ноутбука Core 2 Duo з процесором 2,40 ГГц потрібно приблизно 82 секунди, щоб знайти та роздрукувати прості номери в межах від 1 до 1 000 000. І виявлено 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, який спирається на те, що потрібно перевірити лише основні фактори, тому попередні праймери, згенеровані кодом, повторно використовуються як тестові фактори для пізніших. Звичайно, усі рівні і 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 / (log N) ^ 2), а тестування на праймери нижче квадратного кореня числа - O (N ^ 1,5 / (log N) ^ 2).