В программировании возведение числа в степень — одна из самых распространенных операций. В языке Python для этого есть несколько способов, каждый из которых имеет свои особенности. В данной статье мы рассмотрим методы возведения в степень в Python.
Степень показывает сколько раз число умножается само на себя.
Пример:
Существует три метода, возведения цифр в степень:
um = 3 ** 4 # то же самое что и 3 * 3 * 3 * 3
print(um) # 81
Оператор ** — это простой и универсальный способ возведения в степень, который выбирают многие программисты.
Функция pow() используется для возведения числа степень. Она эквивалентна оператору возведения в степень **.
chislo, stepen = 10, 3
print(pow(chislo, stepen)) # 1000
import math
chislo, stepen = 10, 3
print(math.pow(chislo, stepen)) # 1000.0
Казалось, бы делают они одно и то же, однако есть тонкая разница:
1. pow() может принимать три аргумента: число, степень, остаток от деления
r1 = pow(5, 3) # 5*5*5 = 125
r2 = pow(5, 3, 2) # равносильно (5*5*5) % 2
# то есть остаток от 125 при делении на 2 -> он равен одному
print(r1, r2) # 125 1
2. math.pow() использует ограниченную точность
import math
number, stepen, ostatok = 13, 100, 2
# (13 в степени 100) остаток деления на 2
print(math.pow(number, stepen) % ostatok) # 0.0
print(pow(number, stepen, ostatok)) # 1
Одинаковые действия, но результаты не совпадают. И это может оказаться критичным.
3. math.pow() всегда возвращает float
import math
print(math.pow(2, 6)) # 64.0
print(pow(2, 6)) # 64
Однако если результат дробный, то оба способа вернут float.
import math
print(math.pow(2.1, 6.2)) # 99.48546343115241
print(pow(2.1, 6.2)) # 99.48546343115241
4. math.pow() ломается на больших числах
import math
print(pow(2, 9999)) # без ошибок посчитает
print(math.pow(2, 9999)) # [Фатальная ошибка] OverflowError: math range error
5. Возможная разница в скорости
Напишем код, который измерит скорость выполнения.
pow():
pow1 = """
pow(2, 100)
"""
elapsed_time1 = timeit(pow1, number=100_000)
# запускаем код pow1 100к раз чтобы уменьшить погрешность
print(elapsed_time1)
math.pow():
from timeit import timeit
pow2 = """
import math
math.pow(2, 100)
"""
elapsed_time2 = timeit(pow2, number=100_000) # запускаем код pow2 100к раз
print(elapsed_time2)
Результаты:
pow(): 0.009468599921092391
math.pow(): 0.01545469998382032
Выходит, что pow() быстрее. Однако помните, многое зависит от устройства и платформы, на которой проводится тестирование. Некоторые сообщают, что у них math.pow() намного быстрее 🤔, даже если прописать setup="import math".
На другом компьютере и платформе результаты отличаются:
pow(): 0.013429596998321358
math.pow(): 0.008748997999646235
Здесь math.pow() напротив оказался в полтора раза быстрее.
Возведение в степень также является математической операцией и поддерживается данным модулем.
import numpy
print(numpy.power(2, 30)) # 1073741824
Обычно принято писать «import numpy as np», упрощая тем самым запись до np.power(2, 30).
Если мы создадим последовательность значений через numpy.arrange(), к примеру, то нам открываются некоторые фокусы. Например следующий:
import numpy as np
# input_array
arr1 = np.arange(8)
exponent = 2
print(arr1) # [0 1 2 3 4 5 6 7]
# output_array
out = np.power(arr1, exponent)
print(out) # [ 0 1 4 9 16 25 36 49]
arr1 : [0 1 2 3 4 5 6 7]
Output array : [ 0 1 4 9 16 25 36 49]
С этим arr1 = np.arange(8) теперь можно даже в pow() работать:
print(pow(arr1, 2)) # [ 0 1 4 9 16 25 36 49]
Как мы знаем, 2³¹ = 2147483648, тем не менее, numpy.power(2, 31)
может выдать -2147483648
. Что уже странно, однако numpy.power(2, 32)
вовсе выдаст 0
.
Причина проста, хоть и неожиданна и не особо озвучивается: нужно принудительно указать, чтобы получаемое число под капотом переводилось в тип longint (целое число, которое больше чем 2³¹).
Поэтому исправляем это следующим образом:
numpy.power(2, 31, dtype=numpy.longlong) # получим 2147483648, а не -2147483648
numpy.power(2, 32, dtype=numpy.longlong) # получим 4294967296, а не 0
Давайте сравним скорость работы разных методов возведения числа в степень и выберем оптимальный для наших задач.
from timeit import timeit
# ========== ** ==========
pow1 = """
2**30
"""
elapsed_time1 = timeit(pow1, number=100_000)
# запускаем код pow1 100к раз чтобы уменьшить погрешность
print(elapsed_time1)
# ========== pow() ==========
pow2 = """
pow(2, 30)
"""
elapsed_time2 = timeit(pow2, number=100_000)
print(elapsed_time2)
# ========== math.pow() ==========
pow3 = """
math.pow(2, 30)
"""
elapsed_time3 = timeit(pow3, number=100_000, setup="import math") # запускаем код pow2 100к раз
print(elapsed_time3)
# ========== numpy.power() ==========
pow4 = """
numpy.power(2, 30)
"""
elapsed_time4 = timeit(pow4, number=100_000, setup="import numpy") # запускаем код pow2 100к раз
print(elapsed_time4)
На основе 100000 запусков(number=100_000) получаем следующие результаты:
Место | Метод | Скорость |
---|---|---|
1 | 2**30 | 0.0009847609999837914 |
2 | math.pow(2,30) |
0.007375017000015305 |
3 | pow(2,30) | 0.013787384000011116 |
4 |
numpy.power(2,30) |
0.09736091600001373 |
На порядок быстрее оказался встроенный оператор **. Перевес по времени выполнения pow() и math.pow() может координально измениться от платформы, на которой выполняется код.
При помощи языка Python можно делать математические вычисления. Расмотрим несколько математических трюков.
Корень квадратный — знакомая операция:
Но существует математический трюк, как посчитать корень не запоминая и не путая всякие там sqr/sqrt:
print(9 ** 0.5) # 3.0
print(81 ** 0.5) # 9.0
То есть степень 1/2 это корень квадратный:
print(7 ** -3) # 0.0029154518950437317
Выглядит как что-то страшное. На самом деле всё довольно логично, если представить это дробью:
Пример отрицательной степени:
Поэтому 10-1=0.1
Пример нулевой степени в коде:
print(54532 ** 0) # 1
print(0 ** 0) # 1
Возведение в степень — одна из наиболее часто используемых операций в программировании. В статье были рассмотрены три метода возведения в степень в Python: оператор **, функции pow(), math.pow() и numpy.power().
Самым быстрым и универсальным способом является оператор **. Важно помнить, многое зависит от устройства и платформы, на которой пишется код. Также необходимо учитывать эффективность метода, читаемость и поддерживаемость в будущем.
17 оценок, среднее 4.71 из 5