Как найти простые числа программирование

Алгоритм нахождения простых чисел

Время на прочтение
3 мин

Количество просмотров 432K

Оптимизация алгоритма нахождения простых чисел

2 3 5 7 11 13 17 19 23 29 31… $250.000…

Дело было давно, в университете, когда мы начали изучать язык программирования Pascal и домашним заданием стало создание алгоритма нахождения простых чисел.

Алгоритм был придуман и тутже реализован на изучаемом языке. Программа запрашивала у пользователя число N и искала все простые числа до N включительно. После первого успешного теста сразу же возникло непреодолимое желание ввести N = «много». Программа работала, но не так быстро как хотелось бы. Естественно, дело было в многочисленных проверках (порядка N*N/2), поэтому пришлось избавиться от лишних. В итоге получилось 5 похожих алгоритмов каждый из которых работал быстре предыдущего. Недавно захотелось их вспомнить и реализовать, но на этот раз на Python.

Итак, поехали. Первый алгоритм, ударивший в студенческую голову, продемонстрирован в Листинге 1.

# Листинг 1
# вводим N
n = input("n=")
# создаем пустой список для хранения простых чисел
lst = []
# в k будем хранить количество делителей
k = 0
# пробегаем все числа от 2 до N
for i in xrange(2, n+1):
    # пробегаем все числа от 2 до текущего
    for j in xrange(2, i):
        # ищем количество делителей
        if i % j == 0:
            k = k + 1
    # если делителей нет, добавляем число в список
    if k == 0:
        lst.append(i)
    else:
        k = 0
# выводим на экран список
print lst

Очень быстро понимаешь, что в подсчете делителей каждого числа нет никакой надобности и поэтому переменную k можно освободить от своих обязанностей. Действительно, если хотябы один делитель имеется, то число уже не простое. Смотрим Листинг 2.

# Листинг 2
n = input("n=")
lst = []
for i in xrange(2, n+1):
    for j in xrange(2, i):
        if i % j == 0:
            # если делитель найден, число не простое.
            break
    else:
        lst.append(i)
print lst

Конструкция break позволяет нам завершить выполнение внутреннего цикла и перейти к следующей итерации внешнего.
Далее возникает вопрос: «а зачем делить на 4, если на 2 число не делится?». Приходим к выводу, что искать делители нужно только среди простых чисел не превышающих делимое. Наш алгоритм превращается в… см. Листинг 3.

# Листинг 3
n = input("n=")
lst=[]
for i in xrange(2, n+1):
    # пробегаем по списку (lst) простых чисел
    for j in lst:
        if i % j == 0:
            break
    else:
        lst.append(i)
print lst

А потом вспоминаем теорию чисел и понимаем, что переберать надо только числа, не превосходящие корня из искомого. К примеру, если число M имеет делитель pi, то имеется делитель qi, такой, что pi * qi = M. То есть, чтобы найти пару, достаточно найти меньшее. Среди всех пар, предполагаемая пара с максимальным наименьшим — это пара с равными pi и qi, то есть pi * pi = M => pi = sqrt(M). Смотрим Листинг 4.

# Листинг 4 
from math import sqrt
n = input("n=")
lst=[]
for i in xrange(2, n+1):
    for j in lst:
        if j > int((sqrt(i)) + 1):
            lst.append(i)
            break
        if (i % j == 0):
            break
    else:
        lst.append(i)
print lst

Код из Листинга 4 при N=10000 выполняется примерно в 1000 раз быстрее, чем самый первый вариант. Есть еще один «ускоритель», проверять только те числа, которые заканчиваются на 1, 3, 7 или 9 (так как остальные очевидно делятся на 2 или 5). Наблюдаем Листинг 5.

# Листинг 5
from math import sqrt
n = input("n=")
lst=[]
for i in xrange(2, n+1):
    if (i > 10):
        if (i%2==0) or (i%10==5):
            continue
    for j in lst:
        if j > int((sqrt(i)) + 1):
            lst.append(i)
            break
        if (i % j == 0):
            break
    else:
        lst.append(i)
print lst

В следствии незначительного изменения Листинга 5 получаем небольшую прибавку в скорости:

# Листинг 6
from math import sqrt
n = input("n=")
lst=[2]
for i in xrange(3, n+1, 2):
    if (i > 10) and (i%10==5):
        continue
    for j in lst:
        if j > int((sqrt(i)) + 1):
            lst.append(i)
            break
        if (i % j == 0):
            break
    else:
        lst.append(i)
print lst

Итого: Программа из последнего листинга выполняется, примерно, в 1300 раз быстрее первоначального варианта.
Я не ставил перед собой задачи написать программу максимально быстро решающую данную задачу, это скорее демонстрация начинающим программистам того, что правильно составленный алгоритм играет далеко не последнюю роль в оптимизации Ваших программ.

P.S.
Благодаря замечаниям получаем Листинг 7:

# Листинг 7
n = input("n=")
lst=[2]
for i in xrange(3, n+1, 2):
	if (i > 10) and (i%10==5):
		continue
	for j in lst:
		if j*j-1 > i:
			lst.append(i)
			break
		if (i % j == 0):
			break
	else:
		lst.append(i)
print lst

при N=10000, поучаем время:
time 1 = 26.24
time 2 = 3.113
time 3 = 0.413
time 4 = 0.096
time 5 = 0.087
time 6 = 0.083
time 7 = 0.053

Решето Эратосфена:

# Листинг 8
n = input("n=")
a = range(n+1)
a[1] = 0
lst = []

i = 2
while i <= n:
    if a[i] != 0:
        lst.append(a[i])
        for j in xrange(i, n+1, i):
            a[j] = 0
    i += 1
print lst

Результаты при n = 1 000 000:
time 7 = 7.088
time 8 = 1.143

Given two numbers L and R, the task is to find the prime numbers between L and R.

Examples:

Input: L = 1, R = 10
Output: 2 3 5 7
Explanation:
Prime number between the 1 and 10 are 2, 3, 5, and 7 

Input: L = 30, R = 40
Output: 31 37 

Approach 1:

The idea is to iterate from in the range [L, R] and check if any number in the given range is prime or not. If yes then print that number and check for the next number till we iterate all the numbers.

Below is the implementation of the above approach:

C

#include <stdio.h>

void primeInRange(int L, int R)

{

    int i, j, flag;

    for (i = L; i <= R; i++) {

        if (i == 1 || i == 0)

            continue;

        flag = 1;

        for (j = 2; j <= i / 2; ++j) {

            if (i % j == 0) {

                flag = 0;

                break;

            }

        }

        if (flag == 1)

            printf("%d ", i);

    }

}

int main()

{

    int L = 1;

    int R = 10;

    primeInRange(L, R);

    return 0;

}

C++

#include <bits/stdc++.h>

using namespace std;

void primeInRange(int L, int R)

{

    int flag;

    for (int i = L; i <= R; i++) {

        if (i == 1 || i == 0)

            continue;

        flag = 1;

        for (int j = 2; j <= i / 2; ++j) {

            if (i % j == 0) {

                flag = 0;

                break;

            }

        }

        if (flag == 1)

            cout << i << " ";

    }

}

int main()

{

    int L = 1;

    int R = 10;

    primeInRange(L, R);

    return 0;

}

Time Complexity: O((R-L)*N), where N is the number, and L and R are the given range.
Auxiliary Space: O(1)

Approach 2: (Optimized Approach)

An optimized approach of the above is to check until square root of each value instead of half. We also don’t check even numbers.

Approach:

The approach behind this solution is:

  1. We first print 2 if 2 is in range as 2 is the only even prime number.
  2. Then we iterate all the odd numbers only.
  3. In every iteration we check and print if the number is prime or not using isPrime function.
  4. In isPrime function:
    • We will first deal with a few numbers such as 1, 2, 3 in a case.
    • Then we deal with the numbers which are divisible by 2 and 3 in a separate case.
    • For remaining numbers:
      • Iterate from 5 to sqrt(n) and check for each iteration whether (that value) or (that value + 2) divides n or not.
        • If we find any number that divides, then we return false.
      • Again increment the value by 6 [because any prime can be expressed as 6n+1 or 6n-1]. 
    • If any number can’t divide the number, then we return true.

Below is the implementation of the above approach:

C

#include <stdbool.h>

#include <stdio.h>

bool isPrime(int n)

{

    if (n == 2 || n == 3)

        return true;

    if (n % 2 == 0 || n % 3 == 0)

        return false;

    for (int i = 5; i * i <= n; i = i + 6)

        if (n % i == 0 || n % (i + 2) == 0)

            return false;

    return true;

}

void primeInRange(int L, int R)

{

    if (R >= 2 && L <= 2) {

        printf("2 ");

        L = 3;

    }

    if (L % 2 == 0)

        L++;

    for (int i = L; i <= R; i += 2) {

        if (isPrime(i))

            printf("%d ", i);

    }

}

int main()

{

    int L = 1;

    int R = 10;

    primeInRange(L, R);

    return 0;

}

C++

#include <bits/stdc++.h>

using namespace std;

bool isPrime(int n)

{

    if (n == 2 || n == 3)

        return true;

    if (n % 2 == 0 || n % 3 == 0)

        return false;

    for (int i = 5; i * i <= n; i = i + 6)

        if (n % i == 0 || n % (i + 2) == 0)

            return false;

    return true;

}

void primeInRange(int L, int R)

{

    if (R >= 2 && L <= 2) {

        cout << "2 ";

        L = 3;

    }

    if (L % 2 == 0)

        L++;

    for (int i = L; i <= R; i += 2) {

        if (isPrime(i))

            cout << i << " ";

    }

}

int main()

{

    int L = 1;

    int R = 10;

    primeInRange(L, R);

    return 0;

}

Time Complexity: O((R-L)*sqrt(N)), where N is the number, and L and R are the given range.
Auxiliary Space: O(1)

Approach 3:

An alternative approach to implement the same code would be to use a sieve algorithm. A sieve algorithm starts by creating a list of all the numbers in the desired range and then crossing out the multiples of each prime number. The resulting list will contain only the prime numbers.

C

#include <stdbool.h>

#include <stdio.h>

#include <stdlib.h>

bool* prime;

void sieve(int x, int y)

{

    prime = calloc((y + 1), sizeof(bool));

    for (int i = 2; i <= y; i++) {

        prime[i] = true;

    }

    for (int i = 2; i * i <= y; i++) {

        if (prime[i])

            for (int j = i * i; j <= y; j += i) {

                prime[j] = false;

            }

    }

}

int* allPrime(int l, int r, int* size)

{

    int count = 0;

    for (int i = l; i <= r; i++) {

        if (prime[i]) {

            count++;

        }

    }

    int* result = malloc(count * sizeof(int));

    int j = 0;

    for (int i = l; i <= r; i++) {

        if (prime[i]) {

            result[j++] = i;

        }

    }

    *size = count;

    return result;

}

int main()

{

    int starting_range = 5;

    int ending_range = 100;

    sieve(starting_range, ending_range);

    int size;

    int* result

        = allPrime(starting_range, ending_range, &size);

    if (size == 0) {

        printf("There are no prime numbers in this rangen");

    }

    else {

        printf("The prime numbers in this range are: ");

        for (int i = 0; i < size; i++) {

            printf("%d ", result[i]);

        }

        printf("n");

    }

    free(prime);

    free(result);

    return 0;

}

C++

#include <bits/stdc++.h>

using namespace std;

vector<bool> prime;

void sieve(int x, int y)

{

    prime.resize(y + 1, true);

    prime[1] = false;

    for (int i = 2; i * i <= y; i++) {

        if (prime[i])

            for (int j = i * i; j <= y; j += i) {

                prime[j] = false;

            }

    }

}

vector<int> allPrime(int l, int r)

{

    vector<int> result;

    for (int i = l; i <= r; i++) {

        if (prime[i]) {

            result.push_back(i);

        }

    }

    return result;

}

int main()

{

    int starting_range = 5;

    int ending_range = 100;

    sieve(starting_range, ending_range);

    vector<int> result

        = allPrime(starting_range, ending_range);

    if (result.empty()) {

        cout << "There are no prime numbers in this range"

             << endl;

    }

    else {

        cout << "The prime numbers in this range are: ";

        for (int n : result) {

            cout << n << " ";

        }

        cout << endl;

    }

    return 0;

}

Output

The prime numbers in this range are: 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 

Time Complexity : O(n log(log(n))
Auxiliary Space: (R-l), where R and l are the starting and ending ranges. 

Last Updated :
17 May, 2023

Like Article

Save Article

чтобы проверить что число простое в данном алгоритме он делится на все числа от 2 до int(number / 2) включительно (поэтому и half + 1)

очевидно, что если число не делится на какое-то число в диапазоне 0 ..number / 2, то оно не делится на любое числа в диапазоне number / 2 .. number и поэтому проверять на делимость дальше не нужно

ведь если число a делится на число b из диапазона number / 2 .. number:

c = a / b

то оно делится и на число c из диапазона 0 ..number / 2

Но это неоптимальный алгоритм, потому что достаточно проверить все числа в диапазоне 2 .. sqrt(number) и если число не делится ни на одно число из этого диапазона, то оно простое.

На этом принципе основано решето Эратосфена поиска простых чисел — когда вы рассматриваете только sqrt(n) чисел чтобы найти все простые числа до n

P.S.

по хорошему надо проверить делимость на 2, а дальше в диапазоне проверять только нечётные числа

а еще как только найден делитель — не надо проверять остальные числа и так понятно, что число составное и можно выходить

def is_prime(number):
    if number % 2 == 0:
        return number == 2

    # Локальные переменные
    sqrt_num = int(number**.5)

    for count in range(3, sqrt_num + 1, 2):
        if number % count == 0:
            return False
        
    return True

Содержание

  • Задача №1
  • Алгоритм определения простого числа
  • Реализация алгоритма определения простого числа в C#
  • Пример определения простых чисел из диапазона от 1 до N
  • Пример определения заданного количества простых чисел
  • Итого

уважаемые посетители блога, если Вам понравилась, то, пожалуйста, помогите автору с лечением. Подробности тут.

Простое число — это целое положительное число, имеющее ровно два различных натуральных делителя — единицу и самого себя. Определение того является ли число простым или нет — это одна из самых распространенных задач, решаемых в рамках курса лабораторных работ по информатике. Ниже будет представлена реализация алгоритма поиска простых чисел в C#, а также использование различных циклов для вывода простых чисел.

Задача №1

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

Алгоритм определения простого числа

Для того, чтобы проверить является ли число N простым необходимо:

  1. Задаем значение N
  2. Задаем цикл for от 2 до N-1 (счётчик цикла обозначим, например, как i)
    1. Если остаток от деление N на i равен нулю, то число не является простым — выходим из цикла
    2. Если остаток от деления N на i не равен нулю, то переходим к следующей итерации цикла
  3. Если цикл полностью пройден, то число является простым.

Метод определения простого числа в C#, реализующий представленный выше алгоритм может быть представлен следующим образом:

public bool IsPrime(int number)
{
    for (int i = 2; i < number; i++)
    {
        if (number % i == 0)
            return false;
    }
    return true;
}

Пример определения простых чисел из диапазона от 1 до N

Если по условиям задачи конечное значение диапазона задается в виде числа N, то здесь удобно использовать цикл for или while. Пример программы с использованием цикла for представлен ниже:

using System;

namespace Prime
{
    class Program
    {
        public static bool IsPrime(int number) 
        { 
            for (int i = 2; i < number; i++) 
            { 
                if (number % i == 0) 
                    return false; 
            } 
            return true; 
        }

        static void Main(string[] args)
        {
            Console.WriteLine("Введите конечное значение диапазона 1...N и нажмите Enter");
            Console.WriteLine("N = "); 
            if ((!int.TryParse(Console.ReadLine(), out int result))||(result<0))
                Console.WriteLine("Число должно быть положительным и целым");
            Console.WriteLine($"Простые числа из диапазона от 1 до {result}");
            int count = 0;
            for (int i = 1; i <= result; i++)
            {
                if (IsPrime(i))
                {
                    Console.Write($"{i} ");
                    count++;
                }
            }
            Console.WriteLine("");
            Console.WriteLine($"Найдено {count} простых чисел из диапазона от 1 до {result}");
        }
    }
}

Строго говоря, число 1 не является ни простым не составным, поэтому его можно было бы исключить из цикла, что мы и сделаем в следующем примере.

Пример определения заданного количества простых чисел

Задача поиска простых чисел может быть сформулирована и по другому, например, так: найти первые N простых чисел. В этом случае нам будет выгодно использовать цикл while:

using System;

namespace Prime
{
    class Program
    {
        public static bool IsPrime(int number) 
        { 
            for (int i = 2; i < number; i++) 
            { 
                if (number % i == 0) 
                    return false; 
            } 
            return true; 
        }

        static void Main(string[] args)
        {
            Console.WriteLine("Введите количество простых чисел которые необходимо найти");
            Console.WriteLine("N = "); 
            if ((!int.TryParse(Console.ReadLine(), out int result))||(result<=0))
                Console.WriteLine("Число должно быть положительным и целым");
            Console.WriteLine($"Первые {result} простых чисел");
            int count = 0; //количество найденных простых чисел
            int number = 1; //очередное число, проверку которого необходимо найти
            int total = 0; //общее количество проверенных чисел
            while (count<result)
            {
                total++;
                number++;
                if (IsPrime(number))
                {
                    Console.Write($"{number} ");
                    count++;
                }
            }
            Console.WriteLine("");
            Console.WriteLine($"Найдено {count} простых чисел. Проверено {total} чисел");
        }
    }
}

Результатом работы программы будет вывод в консоль первых N простых чисел.

Итого

Сегодня мы рассмотрели алгоритм поиска простых чисел и реализовали этот алгоритм в C#. В зависимости от условий задачи, мы использовали различные виды циклов для поиска набора простых чисел.

уважаемые посетители блога, если Вам понравилась, то, пожалуйста, помогите автору с лечением. Подробности тут.

Описание задачи

Программа принимает на вход число и проверяет, простое оно или нет.

Решение задачи

  1. Принимаем на вход число и записываем его в отдельную переменную.
  2. Инициализируем переменную, которая будет выполнять роль счетчика, значением 0.
  3. Организуем цикл for в диапазоне от 2 до значения проверяемого числа, деленного на 2 (речь идет, конечно, о целочисленном делении).
  4. Затем находим количество делителей нашего числа. При помощи условного оператора if мы проверяем, делится ли число без остатка, и затем, если делится, увеличиваем наш счетчик на единицу.
  5. Если число делителей равно 0, то проверяемое число является простым.
  6. Выводим результат на экран.
  7. Конец.

Исходный код

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

a = int(input("Введите число: "))
k = 0
for i in range(2, a // 2+1):
    if (a % i == 0):
        k = k+1
if (k <= 0):
    print("Число простое")
else:
    print("Число не является простым")

Объяснение работы программы

  1. Пользователь вводит число, и оно сохраняется в переменную a.
  2. Инициализируем переменную k значением 0. Эта переменная будет выполнять роль счетчика.
  3. Запускаем цикл for в диапазоне от 2 до значения проверяемого числа, деленного на 2 (речь идет, конечно, о целочисленном делении). Напоминаем, что само число и 1 делителями мы считать не будем.
  4. Затем, при помощи инструкции if, на каждой итерации цикла мы проверяем, делится ли наше число без остатка на числа из выбранного диапазона цикла. Если делится, то переменная k, выполняющая роль счетчика, увеличивается на единицу.
  5. Если число делителей равно 0, то проверяемое число является простым.
  6. Выводим полученный результат на экран.

Результаты работы программы

Пример 1:
Введите число: 7
Число простое
 
Пример 2:
Введите число: 35
Число не является простым

Еще более 50 задач на числа в нашем телеграм канале Python Turbo. Уютное сообщество Python разработчиков.

Понравилась статья? Поделить с друзьями:

Не пропустите также:

  • Как найти серийный номер материнской платы asus
  • Как составить словосочетание словом школа 5 класс
  • Как исправить флешку полностью
  • Как найти минусовку по звуку
  • Как найти судебного пристава по адресу должника

  • 0 0 голоса
    Рейтинг статьи
    Подписаться
    Уведомить о
    guest

    0 комментариев
    Старые
    Новые Популярные
    Межтекстовые Отзывы
    Посмотреть все комментарии