Як перевірити, чи число є простим у Python

Цей підручник навчить вас, як написати програму на Python, щоб перевірити, чи число є простим чи ні.

Якщо ви коли-небудь проходили тести з програмування, ви натрапили на математичне запитання в тесті на простоту чи перевірку того, чи число є простим. І протягом наступних кількох хвилин ви навчитеся придумувати оптимальне рішення цього питання.

У цьому посібнику ви:

  • повторити основи простих чисел,
  • написати код Python, щоб перевірити, чи число є простим, і
  • оптимізуйте його далі, щоб отримати алгоритм виконання O(√n).

Для всього цього та іншого давайте почнемо.

Що таке просте число?

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

У теорії чисел — натуральне число n простий якщо воно має рівно два множники: 1 і саме число (n). Згадайте зі шкільної математики: число i називається множником числа n, якщо i ділить n порівну. ✅

У наступній таблиці наведено кілька чисел, усі їхні множники та чи є вони простими.

nЧильники є простими? 11No21, 2Yes31, 3Yes41, 2, 4No71, 7Yes151, 3, 5, 15No

З наведеної вище таблиці ми можемо записати наступне:

  • 2 — найменше просте число.
  • 1 є множником кожного числа.
  • Кожне число n є множником саме по собі.

Отже, 1 і n є тривіальними множниками для будь-якого числа n. І просте число не повинно мати жодних множників, крім цих двох.

Це означає, що коли ви переходите від 2 до n – 1, ви не зможете знайти нетривіальний множник, який ділить n без залишку.

O(n) Алгоритм для перевірки, чи число є простим у Python

У цьому розділі давайте формалізуємо наведений вище підхід у функцію Python.

Ви можете прокрутити всі числа від 2 до n – 1 за допомогою об’єкта range() у Python.

У Python діапазон (початок, зупинка, крок) повертає об’єкт діапазону. Потім ви можете виконати ітерацію по об’єкту діапазону, щоб отримати послідовність від початку аж до зупинки -1 з кроком.

  Як змусити Find My iPhone шуміти під час пошуку пристрою

Оскільки нам потрібен набір цілих чисел від 2 до n-1, ми можемо вказати діапазон (2, n) і використовувати його в поєднанні з циклом for.

Ось що ми хотіли б зробити:

  • Якщо ви знайдете число, яке ділить n порівну без залишку, ви можете відразу зробити висновок, що це число не є простим.
  • Якщо ви прокрутили весь діапазон чисел від 2 аж до n – 1, не знайшовши числа, яке ділить n порівну, тоді число є простим.

Функція Python для перевірки простого числа

Використовуючи вищесказане, ми можемо продовжити та визначити функцію is_prime() наступним чином.

def is_prime(n):
  for i in range(2,n):
    if (n%i) == 0:
      return False
  return True

Давайте тепер розберемо наведене вище визначення функції.

  • Наведена вище функція is_prime() приймає натуральне число n як аргумент.
  • Якщо ви знайдете множник у вказаному діапазоні (2, n-1), функція повертає False, оскільки число не є простим.
  • І він повертає True, якщо ви проходите весь цикл, не знаходячи фактора.

Далі викличемо функцію з аргументами та перевіримо, чи правильний результат.

is_prime(2)
# True

is_prime(8)
# False

is_prime(9)
# False

is_prime(11)
# True

У вихідних даних вище ви бачите, що 2 і 11 є простими (функція повертає True). А 8 і 9 не є простими (функція повертає False).

Як оптимізувати функцію Python is_prime()

Тут ми можемо зробити невелику оптимізацію. Зверніть увагу на перелік факторів у таблиці нижче.

NumberFactors61, 2, 3, 6101, 2, 5, 10181, 2, 3, 6, 9, 18

Отже, ми бачимо, що єдиний множник n, який більший за n/2, це саме n.

Отже, це означає, що вам не потрібно виконувати цикл до n – 1. Натомість ви можете запустити цикл лише до n/2.

Якщо ви не знайдете нетривіальний множник до n/2, ви також не зможете знайти такий, що перевищує n/2.

Тепер модифікуємо функцію is_prime(), щоб перевірити фактори в діапазоні (2, n/2)

def is_prime(n):
  for i in range(2,int(n/2)):
    if (n%i) == 0:
      return False
  return True

Давайте перевіримо результат за допомогою кількох викликів функцій.

is_prime(9)
# False

is_prime(11)
# True

Незважаючи на те, що може здатися, що ми оптимізували, цей алгоритм не ефективніший за попередній з точки зору складності виконання. Фактично, обидва вони мають O(n) складність часу виконання: пропорційну значенню n або лінійну в n.

  10 найкращих платформ для автоматизації робочого процесу та інтеграції для особистого чи бізнес-класу

Чи можемо ми зробити краще? Так, ми можемо!

▶️ Перейдіть до наступного розділу, щоб визначити, як покращити часову складність для перевірки простих чисел.

O(√n) Алгоритм перевірки простого числа в Python

Буває, що множники числа зустрічаються парами.

Якщо a є множником числа n, то існує також такий множник b, що axb = n, або просто ab = n.

Переконаємося в цьому на прикладі.

У таблиці нижче наведено множники числа 18, що зустрічаються в парах. Ви можете підтвердити те саме для кількох інших номерів, якщо хочете.

Також зауважте, що √18 дорівнює приблизно 4,24.

А в факторах, які зустрічаються в парах (a, b), ви можете побачити, що якщо a менше 4,24, то b більше 4,24—у цьому прикладі (2, 18) і (3, 6).

Множники числа 18 попарно

На малюнку нижче показано множники числа 18, нанесені на числову пряму.

Якщо число n є повним квадратом, ви матимете a = b = √n як один із множників.

▶️ Подивіться на множники 36 у таблиці нижче. Оскільки 36 є повним квадратом, a = b = 6 є одним із множників. Для всіх інших пар факторів (a, b) виконується a < 6 і b > 6.

Множники числа 36 попарно

Підводячи підсумок, маємо наступне:

  • Кожне число n можна записати як n = axb
  • Якщо n — повний квадрат, то a = b = √n.
  • А якщо a < b, то a < √n і b > √n.
  • Інакше, якщо a > b, то a > √n і b < √n.

Тож замість того, щоб перебирати всі цілі числа до n/2, ви можете вибрати виконання до √n. І це набагато ефективніше, ніж наш попередній підхід.

Як змінити алгоритм is_prime() на O(√n).

Давайте приступимо до оптимізації функції для перевірки простих чисел у Python.

import math
def is_prime(n):
  for i in range(2,int(math.sqrt(n))+1):
    if (n%i) == 0:
      return False
  return True

Тепер розберемо наведене вище визначення функції:

  • Щоб обчислити квадратний корінь із числа, давайте імпортуємо вбудований математичний модуль Python і використаємо функцію math.sqrt().
  • Оскільки n може бути не ідеальним квадратом, нам доведеться перетворити його на ціле число. Використовуйте int(var), щоб перетворити var в int.
  • Щоб переконатися, що ми справді перевіряємо √n, ми додаємо плюс один, оскільки функція range() за замовчуванням виключає кінцеву точку діапазону.
  15 найкращих платформ Wiki для вашого бізнесу

Комірка коду нижче перевіряє, чи наша функція is_prime() працює правильно.

is_prime(8)
# False

is_prime(15)
# False

is_prime(23)
# True

У наступному розділі створимо кілька простих графіків, щоб візуально зрозуміти O(n) і O(√n).

Візуальне порівняння O(n) і O(√n).

▶️ Запустіть наведений нижче фрагмент коду в середовищі блокнота Jupyter за вашим вибором.

import numpy as np
import seaborn as sns
import pandas as pd


n = 20

x = np.arange(n)
y1 = np.sqrt(x)
y2 = x
df = pd.DataFrame({"O(√n)":y1,"O(n)":y2})
sns.set_theme()
sns.lineplot(data = df)

Наведений вище фрагмент показує, як можна побудувати криві для n і √n для діапазону значень.

  • Ми використовуємо функцію NumPy arange(), щоб створити масив чисел.
  • Потім ми збираємо значення n і √n до 20, але не включаючи, у pandas DataFrame.
  • Далі малюємо за допомогою лінія Сіборна() функція.

З наведеного нижче графіка ми бачимо, що √n значно менше за n.

Давайте тепер збільшимо діапазон до 2000 і повторимо ті самі кроки, що й вище.

import numpy as np
import seaborn as sns
import pandas as pd


n = 2000

x = np.arange(n)
y1 = np.sqrt(x)
y2 = x
df = pd.DataFrame({"O(√n)":y1,"O(n)":y2})
sns.set_theme()
sns.lineplot(data = df)

З наведеного вище графіка можна зробити висновок, що алгоритм O(√n) значно швидший, коли ви перевіряєте, чи велике число є простим.

Ось короткий приклад: 2377 є простим числом — переконайтеся в цьому!😀

У той час як підхід O(n) займає близько 2000 кроків, алгоритм O(√n) може допомогти отримати відповідь лише за 49 кроків.✅

Висновок

⏳ І настав час коротко підвести підсумки.

  • Щоб перевірити, чи число є простим, наївний підхід полягає в тому, щоб прокрутити всі числа в діапазоні (2, n-1). Якщо ви не знайдете множник, який ділить n, то n є простим числом.
  • Оскільки єдиним множником n, більшим за n/2, є саме n, ви можете запустити лише до n/2.
  • Обидва вищезазначені підходи мають часову складність O(n).
  • Оскільки множники числа зустрічаються парами, ви можете працювати лише до √n. Цей алгоритм набагато швидший, ніж O(n). І виграш помітний при перевірці, чи велике число є простим чи ні.

Сподіваюся, ви розумієте, як перевірити, чи число є простим у Python. Наступним кроком ви можете ознайомитися з нашим підручником із програм Python щодо операцій із рядками, де ви навчитеся перевіряти, чи є рядки паліндромами, анаграмами тощо.

До зустрічі в іншому підручнику. А поки бажаємо щасливого кодування!👩🏽‍💻