В Дзене Python есть принцип, согласно которому "должен существовать один и желательно только один очевидный способ сделать это". Однако в Python есть как минимум три способа возведения числа в степень:
-
оператор
**
-
встроенная функция
pow()
-
функция
math.pow()
В этой статье мы рассмотрим каждый из способов и разберемся, чем они отличаются.
Оператор **
Оператор **
— это классический оператор возведения в степень. Это в принципе первое, что обычно приходит в голову любому программисту на Python, когда требуется возвести число в степень.
Приведенный ниже код:
print(2 ** 10) # 2 в 10-й степени
print(10 ** 2) # 10 во 2-й степени
выводит:
1024
100
Важно отметить, что оператор **
работает со всеми числовыми типами в Python: int, float, Fraction, Decimal, complex
.
Приведенный ниже код:
from fractions import Fraction
from decimal import Decimal
nums = [100, 0.3, Fraction(2, 5), Decimal('0.3'), complex(3, 7)]
for num in nums:
print(num ** 2)
выводит:
10000
0.09
4/25
0.09
(-40+42j)
Следует сказать, что оператор возведения в степень **
является правоассоциативным, то есть выражение x ** y ** z
вычисляется справа налево и трактуется как x ** (y ** z)
, а не как (x ** y) ** z
.
Приведенный ниже код:
print(2 ** 3 ** 4) # 2 в 81-й степени
print((2 ** 3) ** 4) # 8 в 4-й степени
выводит:
2417851639229258349412352
4096
Встроенная функция pow()
Встроенная функция pow()
принимает два обязательных аргумента, первый из которых base
— это число, которое необходимо возвести в определенную степень, а второй exp
— собственно, сама степень.
Приведенный ниже код:
print(pow(2, 10)) # 2 в 10-й степени
print(pow(10, 2)) # 10 во 2-й степени
выводит:
1024
100
Следует отметить, что функция pow()
, как и оператор **
, работает со всеми числовыми типами в Python, а также имеет аналогичную производительность, то есть выполняется примерно за такое же время.
Возникает резонный вопрос: зачем использовать данную функцию, когда есть простой и понятный оператор **
? Дело в том, что функция pow()
также может принимать необязательный аргумент mod
, с помощью которого она возводит число в степень по модулю. Другими словами, она возвращает число, которое является остатком от деления результата возведения в степень на число mod
.
Приведенный ниже код:
print(pow(2, 10, 15)) # 2 в 10-й степени по модулю 15
print(pow(10, 2, 15)) # 10 во 2-й степени по модулю 15
выводит:
4
10
Несложно заметить, что аналогичного результата можно добиться с использованием связки операторов **
и %
.
Приведенный ниже код:
print(2 ** 10 % 15) # 2 в 10-й степени по модулю 15
print(10 ** 2 % 15) # 10 в 2-й степени по модулю 15
выводит:
4
10
И снова возникает вопрос: зачем использовать функцию pow()
, если можно легко обойтись операторами **
и %
? Оказывается, в отличие от оператора **
, функция pow()
при возведении числа в степень по модулю за кулисами использует оптимизированный алгоритм, который не вычисляет результат возведения в степень явно, как это делает оператор **
.
Приведенный ниже код:
from timeit import timeit
power_by_stars = '''
number = 2
power = 10000
number ** power % 100
'''
power_by_pow = '''
number = 2
power = 10000
pow(number, power, 100)
'''
print('Возведение в степень по модулю с помощью оператора **:', timeit(power_by_stars, number=1_000_000), 'с.')
print('Возведение в степень по модулю с помощью функции pow():', timeit(power_by_pow, number=1_000_000), 'с.')
выводит (результат может незначительно отличаться):
Возведение в степень по модулю с помощью оператора **: 10.867430499754846 с.
Возведение в степень по модулю с помощью функции pow(): 0.17797810025513172 с.
В результате приведенного эксперимента получили, что функция pow()
выполняет операцию возведения в степень по модулю намного быстрее операторов **
и %
. Ее время выполнения примерно в 60
раз меньше времени выполнения связки операторов **
и %
.
Возведение в степень по модулю — это операция, которая играет ключевую роль в областях, связанных с криптографией, теорией чисел, алгоритмами шифрования и безопасной передачей данных. Она лежит в основе алгоритма RSA, который используется для шифрования и дешифрования сообщений.
Исходный код функции pow()
доступен по ссылке. Python использует алгоритм быстрого возведения в степень, схему "справа налево".
Функция math.pow()
Третий способ возведения в степень подразумевает использование функции pow()
встроенного модуля math
. Эта функция также принимает два аргумента: число и степень — и возвращает результат возведения числа в степень.
Приведенный ниже код:
import math
print(math.pow(2, 10)) # 2 в 10-й степени
print(math.pow(10, 2)) # 10 во 2-й степени
выводит:
1024.0
100.0
В отличие от оператора **
и встроенной функции pow()
, функция math.pow()
всегда неявно преобразует входные аргументы в вещественные числа (тип float
) и соответственно возвращает результат в виде такого же вещественного числа.
Учитывая эту особенность, функцию math.pow()
необходимо применять с осторожностью. Как известно, вещественные числа (тип float
) имеют ограниченный диапазон значений в отличие от тех же целых чисел (тип int
). Поэтому если результат возведения в степень окажется достаточно большим, то это приведет к возникновению ошибки переполнения.
Приведенный ниже код:
import math
print(math.pow(2, 10000))
приводит к возникновению ошибки переполнения:
OverflowError: math range error
Следует также отметить, что функция pow()
встроенного модуля math
не поддерживает возведение в степень комплексных чисел, поскольку не существует неявного преобразования из комплексного числа (тип complex
) в вещественное (тип float
).
Заключение
Выбирая между встроенными способами возведения в степень, следует отдать предпочтение тем, которые окажутся наиболее полезны и эффективны в той или иной ситуации.
Например, оператор **
позволяет быстро выполнить возведение в степень для получения результата "на лету", а встроенная функция pow()
позволяет выполнить возведение в степень по модулю. Функция math.pow()
не является достаточно точной, однако она все равно может оказаться полезной при вычислении небольших степеней, особенно если результат необходим в виде вещественного числа.
А вы знали, что оператор **
как оператор возведения в степень впервые появился в языке программирования Fortran (Formula Translation)? Возможно, именно поэтому создатели Python решили использовать именно его вместо общепринятого символа каретки ^
, который в Python отвечает за оператор побитового исключающего ИЛИ (XOR).
Присоединяйтесь к нашему телеграм-каналу, будет интересно и познавательно!
❤️Happy Pythoning!🐍
Автор: Тимур Гуев