Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.68/735: Рейтинг темы: голосов - 735, средняя оценка - 4.68
Эксперт С++
4267 / 2241 / 203
Регистрация: 26.08.2011
Сообщений: 3,802
Записей в блоге: 5
1

Быстрая проверка натурального числа на простоту

29.09.2012, 21:35. Показов 139291. Ответов 121
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Часто возникает задача проверки натурального числа на простоту. При этом имеются вероятностные и детерминированные методы проверки. Здесь рассматриваются только детерминированные алгоритмы, дающие 100% ответ на вопрос о простоте.

Хорошо известно такое утверждение: если натуральное число n>1 не делится ни на одно простое число, не превосходящее https://www.cyberforum.ru/cgi-bin/latex.cgi?\sqrt{n}, то оно простое. В связи с этим получается самый простой способ проверки на простоту алгоритм

C++
1
2
3
4
5
6
7
8
9
10
11
int Prime(unsigned long a)
{
   unsigned long i;
   if (a == 2)
      return 1;
   if (a == 0 || a == 1 || a % 2 == 0)
      return 0;
   for(i = 3; i*i <= a && a % i; i += 2)
      ;
   return i*i > a;
}
В данном алгоритме из множества https://www.cyberforum.ru/cgi-bin/latex.cgi?\{2,3,...,\sqrt{n}\} отброшено 50% четных чисел, так как если число a не делится на 2, то нет смыла делить его на 4, 6 и т.д. Данный метод можно усовершенствовать и отбросить из множества https://www.cyberforum.ru/cgi-bin/latex.cgi?\{2,3,...,\sqrt{n}\} больше чисел. Для этого выбирается некоторое число m, равное произведению простых чисел без степеней и рассматриваются только те элементы множества https://www.cyberforum.ru/cgi-bin/latex.cgi?\{2,3,...,\sqrt{n}\}, которые взаимно просты с m. Например, если m = 6 = 2*3, то из этого множества отбрасывается 66% элементов (ненужных проверок). В этом случае алгоритм будет быстрее предыдущего при больших n

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
int Prime(unsigned long a)
{
   unsigned long i, j, bound;
   if (a == 0 || a == 1)
      return 0;
   if (a == 2 || a == 3 || a == 5)
      return 1;
   if (a%2 == 0 || a%3 == 0 || a%5 == 0)
      return 0;
   bound = sqrt((double)a);
   i = 7; j = 11;
   while (j <= bound && a%i && a%j)
   {
       i += 6; j += 6;
   }
   if (j <= bound || i <= bound && a%i == 0)
      return 0;
   return 1;
}
Если m = 30 = 2*3*5, то такой алгоритм будет еще быстрее и отбрасывает уже 74% лишних элементов

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
int Prime(unsigned long a)
{
   unsigned long i1, i2, i3, i4, i5, i6, i7, i8, bound;
   if (a == 0 || a == 1)
      return 0;
   if (a == 2 || a == 3 || a == 5 || a == 7 || a == 11 || a == 13 || a == 17 || a == 19 || a == 23 || a == 29)
      return 1;
   if (a%2 == 0 || a%3 == 0 || a%5 == 0 || a%7 == 0 || a%11 == 0 || a%13 == 0 || a%17 == 0 || a%19 == 0 || a%23 == 0 || a%29 == 0)
      return 0;
   bound = sqrt((double)a);
   i1 = 31; i2 = 37; i3 = 41; i4 = 43; i5 = 47; i6 = 49; i7 = 53; i8 = 59;
   while (i8 <= bound && a%i1 && a%i2 && a%i3 && a%i4 && a%i5 && a%i6 && a%i7 && a%i8)
   {
       i1 += 30; i2 += 30; i3 += 30; i4 += 30; i5 += 30; i6 += 30; i7 += 30; i8 += 30;
   }
   if (i8 <= bound ||
      i1 <= bound && a % i1 == 0 ||
      i2 <= bound && a % i2 == 0 ||
      i3 <= bound && a % i3 == 0 ||
      i4 <= bound && a % i4 == 0 ||
      i5 <= bound && a % i5 == 0 ||
      i6 <= bound && a % i6 == 0 ||
      i7 <= bound && a % i7 == 0)
         return 0;
   return 1;
}
Вот такие интересные наработки получились. У кого есть варианты, работающие быстрее, добавляйте.
33
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
29.09.2012, 21:35
Ответы с готовыми решениями:

Проверка на простоту числа
как мне сделать так, чтобы узнать простое является число или составное, не через bool, а как-нибудь...

Проверка числа на простоту
Помогите написать программу которая проверяет простое число или нет.

Проверка числа на простоту
Дано натуральное число n&gt;1. Проверьте, является ли оно простым. Программа должна вывести слово YES,...

Проверка числа на простоту
Хочу проверить число на простоту, но не вижу ошибку в коде. Можете подсказать, что не так? ...

121
24 / 3 / 0
Регистрация: 28.10.2012
Сообщений: 35
01.11.2012, 19:26 61
Author24 — интернет-сервис помощи студентам
ValeryS, да, я там потом решил этот вопрос, все дело было в этом операторе:
C++
1
ulong d = 1 << 35;
а надо было
C++
1
ulong d = (ulong)1 << 35;
Добавлено через 9 часов 24 минуты
Thinker, в общем написал алгоритм, может его стоит оптимизировать, потому что по скорости он проигрывает в 8 раз! и уже для 128 битных чисел нужно много времени. Даже для числа 265 252 859 812 191 058 636 308 479 999 999 (11*3 = 33 знака) нужно проверить 1,6 * 1016 делителей. И если скорость 2 * 109 / сек, то получаем 1,6 * 1016 / (2 * 109) = 8 * 106 сек или 92 дня.

Вот собственно функции:
mask[i] хранит заранее записанную маску, у которой все единицы начиная от самого левого бита и до i, или по простому - выделяем i бит слева.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
inline __device__ void Search(ulong a,int n, int &ret)
{
    while (n)
    {
        n >>= 1;
        if (a >> n)
        {
            ret += n;
            a >>= n;
        }
    }
}
 
__device__ void LongMod(ulong *digit, ulong count, ulong modl, int bit, ulong &ret)
{
    int how_bit = BIT;
 
    ulong digit_del = digit[0];
    ulong part = digit[1];
    ulong mod = 0;
 
    mod = digit_del % modl;
    for( ;how_bit > 0; )
    {       
        int bitLeft = 0;
        Search(mod,bit,bitLeft);
        bitLeft = BIT - bitLeft - 1;
        if(how_bit >= bitLeft)
        {
            digit_del = mod << bitLeft;
            digit_del |= (part & mask[bitLeft]) >> (BIT - bitLeft);
            part <<= bitLeft;
            how_bit -= bitLeft;
        }
        else if(how_bit > 0)
        {
            digit_del = mod << how_bit;
            digit_del |= (part & mask[how_bit]) >> (BIT - how_bit);
            how_bit = 0;
        }
        mod = digit_del % modl;
    }
    ret = mod;
}
0
Эксперт С++
4267 / 2241 / 203
Регистрация: 26.08.2011
Сообщений: 3,802
Записей в блоге: 5
01.11.2012, 19:39  [ТС] 62
AEXks, ну, ваше стремление похвально, но а на что вы расчитывали, используя длинную арифметику и алгоритм проверки на простоту экспоненциальной сложности относительно количества цифр. Так и должно быть, поэтому я побаловался этим и забросил))
Вы поймите, алгоритм должен зависеть не от аппаратуры (CPU, GPU и т.д.), а от теоретической сложности, а иначе смысла не было бы во многих криптоалгоритмах
0
24 / 3 / 0
Регистрация: 28.10.2012
Сообщений: 35
01.11.2012, 19:43 63
так алгоритм АКС быстрее это делает?
0
Эксперт С++
4267 / 2241 / 203
Регистрация: 26.08.2011
Сообщений: 3,802
Записей в блоге: 5
01.11.2012, 19:45  [ТС] 64
если честно, то не знаю, времени не было его проверить. но у него заявленная сложность полиномиальная относительно количества цифр, то есть обещает быть быстрым. но оять же, не настолько быстрым, чтобы какие-то криптоалгоритмы упали бы.
0
24 / 3 / 0
Регистрация: 28.10.2012
Сообщений: 35
01.11.2012, 20:22 65
Thinker, может попробуете тогда для CPU реализовать хотя бы?
0
Эксперт С++
4267 / 2241 / 203
Регистрация: 26.08.2011
Сообщений: 3,802
Записей в блоге: 5
01.11.2012, 21:03  [ТС] 66
надо будет теоремы почитать с доказательствами, а иначе нет смысла алгоритм составлять. будет время, посмотрю. с другой стороны, почему его так и не реализовали, по крайней мере, не видел реализацию. это, наверное, потому что есть гипотеза (недоказанная), которая значительно ускоряет алгоритм AKS
0
24 / 3 / 0
Регистрация: 28.10.2012
Сообщений: 35
01.11.2012, 21:34 67
Thinker, на паскале вроде говорят есть реализация
0
Эксперт С++
4267 / 2241 / 203
Регистрация: 26.08.2011
Сообщений: 3,802
Записей в блоге: 5
01.11.2012, 21:38  [ТС] 68
AEXks, как же вас зацепила эта задача) может вам имеет смысл в сторону вероятностных алгоритмов посмотреть
0
24 / 3 / 0
Регистрация: 28.10.2012
Сообщений: 35
01.11.2012, 21:47 69
Thinker, они же не дают точный результат
0
Эксперт С++
4267 / 2241 / 203
Регистрация: 26.08.2011
Сообщений: 3,802
Записей в блоге: 5
01.11.2012, 21:49  [ТС] 70
ну, да, а другие алгоритмы (детерминированные) не отличаются скоростью. нужен компромисс)
0
24 / 3 / 0
Регистрация: 28.10.2012
Сообщений: 35
01.11.2012, 21:50 71
Thinker, а вероятностные на много быстрее?
0
Эксперт С++
4267 / 2241 / 203
Регистрация: 26.08.2011
Сообщений: 3,802
Записей в блоге: 5
01.11.2012, 21:51  [ТС] 72
конечно, а иначе не было бы смысла в их использовании.
0
Котовчанин
942 / 482 / 200
Регистрация: 16.02.2010
Сообщений: 3,338
Записей в блоге: 37
22.01.2014, 18:38 73
Написала когда-то программку, которая, с использованием решета Эратосфена, находит все простые и возвращает самый большой простой делитель числа. Код не идеален, потому как новичок ещё я, но работает быстро.
Буду рада советам!

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
#include <iostream>
#include <cassert>
#include <math.h>
#include <sstream>
#include <string>
#include <vector>
 
 
std::vector<int> sieve(int num)
{
    int p = 2;
    std::vector <int> s;
    for (int i = 0; i < num; i++)
    {
        s.push_back(i);
    }
    s.at(1) = 1;
 
    while (p < num)
    {
        if (s.at(p)!=0)
        {
        for (int i = p*2; i < num; i += p)
            {
                 s.at(i) = 0;
            }
        }
        p++;
    }
    return s;
}
 
int prime_factor(std::vector<int> vec, unsigned long long div)
{
    int prime = 0;
    for (int i = 0; i < std::sqrtl(div) - 1; i++)
    {
        if (vec.at(i) == 0) {continue;}
        if (div % vec.at(i) == 0)
        {
            prime = vec.at(i);
        }
        i++;
    }
    return prime;
}
 
int solve(unsigned long long num)
{
    std::vector<int> array; 
    int prime;
    int count = std::sqrtl(num);
    array = sieve(count);
    prime = prime_factor(array, num);
    return prime;
}
 
void main(int argc, char *argv[])
{
    unsigned long long arg = 1;
    if (argc >= 1)
    {
        std::stringstream ss;
        ss << argv[1];
        ss >> arg;
    }
    std::cout << solve(arg) << std::endl;
 
}
0
4165 / 1817 / 216
Регистрация: 06.10.2010
Сообщений: 4,074
18.07.2014, 12:07 74
А все таки как определить номер старшего бита числа
C
1
2
3
4
5
6
7
8
int __declspec(naked) _cdecl bsr(int x)
{
    _asm
    {
        bsr eax,[esp+4]
        ret
    }
}
Добавлено через 9 минут
А ещё на AMD есть какой-то сумасшедший набор инструкций - TBM, возможно его удастся применить к этой задаче.
0
Master of Orion
Эксперт .NET
6098 / 4954 / 905
Регистрация: 10.07.2011
Сообщений: 14,522
Записей в блоге: 5
18.07.2014, 12:34 75
Мне кажется, простейший способ - написать прогармму с кодогенерацией, которая сгенерирует метод, который будет проверять все числа Например взять первые 100 простых чисел, и сгенерировать файлик, где
C++
1
2
3
4
5
6
7
8
if (x == a1 || x == a2 || ...)
   return false;
int sqrt = sqrt_int(x);
int step = std::accumulate(...) //тут получаем произведение всех этих простых чисел. Хотя тут уже double наверное нужно юзать, в int вряд ли влезет
for(int i = 0; i < sqrt; i+=)
   if (x%i == 0)
      return false;
return true;
достаточно заранее найти 100 первых простых чисел (тем же эратосфеном).
0
Модератор
Эксперт по электронике
8908 / 6677 / 918
Регистрация: 14.02.2011
Сообщений: 23,521
18.07.2014, 12:48 76
Цитата Сообщение от Psilon Посмотреть сообщение
достаточно заранее найти 100 первых простых чисел (тем же эратосфеном).
если ты внимательно читал тему то заметил что это уже предлагалось
да и речь то идет не о первых 100 числах а о числах порядка 264 и выше
Цитата Сообщение от murderer Посмотреть сообщение
А ещё на AMD есть какой-то сумасшедший набор инструкций - TBM, возможно его удастся применить к этой задаче.
а еще есть 100500 разных процессоров
решалась задача в общем
0
Master of Orion
Эксперт .NET
6098 / 4954 / 905
Регистрация: 10.07.2011
Сообщений: 14,522
Записей в блоге: 5
18.07.2014, 12:57 77
ValeryS, да, я видел. Но вопрос именно в кодогенерации Прочем не важно. В любом случае для достаточно больших чисел погрешность не даст нормально сказать, какое это число (double без потерь показывает лишь 15 знаков же), а для длинной арифметики слишком много всего писать надо. Вот в лиспе....
0
88 / 84 / 31
Регистрация: 18.11.2013
Сообщений: 390
15.06.2015, 15:03 78
а можно добавить условие в начало:

if(n%6==1 || n%6==5)
return не простое
else проверять по другому

ну и проверять при помощи деления на числа удовлетворяющие условию

Добавлено через 2 минуты
переходите на java или python, на java есть BigInt, а на python всё вообще динамически расширяется
0
267 / 256 / 23
Регистрация: 04.04.2012
Сообщений: 546
17.06.2015, 22:55 79
Цитата Сообщение от Krock21rus Посмотреть сообщение
if(n%6==1 || n%6==5)
return не простое
else проверять по другому
n=7, n%6=1, n -- простое. Не знаю, может, просто вашу мысль не понял...
0
88 / 84 / 31
Регистрация: 18.11.2013
Сообщений: 390
17.06.2015, 23:44 80
Ой, извините, наоборот, там надо так:

C++
1
2
3
if(n%6==1 || n%6==5)
Проверять его
else return не простое
вот здесь вы не найдёте примера
0
17.06.2015, 23:44
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
17.06.2015, 23:44
Помогаю со студенческими работами здесь

Проверка числа на простоту
Написать программу, которая запрашивает массив натуральных чисел (ввод с клавиатуры), а затем...

Проверка числа на простоту
Помогите решить 2 задачки, пожалуйста, 1. Написать программу для проверки натурального числа N...

Проверка числа на простоту
я реализовал вот так, но алгоритм очень долгий, мне надо проверять очень большое количество чисел...

Проверка числа на простоту
Дано натуральное число N, проверить, простое оно или нет. Увеличить его значение на натуральное...

Проверка числа на простоту
Почему, если необ. проверить, является ли число простым(напр. ч-ло n),можно просматривать делители...

Проверка числа на простоту (нужны комментарии)
объясните пожалуйста, как в данной функции выполняется проверка числа на простоту. как можно...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
80
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru