Меню
Каталог
Каталог
Все статьи
Программирование

Возведение в степень на Python

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

Владислав Громов Владислав Громов SEO-специалист
Возведение в степень на Python

Что такое степень?

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

Пример:

2³ = 2 * 2 * 2 = 8 — два в третьей степени.

Существует три метода, возведения цифр в степень:

  • Легкий
  • Средний
  • Сложный
Рассмотрим каждый поподробнее.

Легкий уровень

Для возведения в степень можно использовать оператор **.

um = 3 ** 4  # то же самое что и 3 * 3 * 3 * 3
print(um)  # 81

Оператор ** — это простой и универсальный способ возведения в степень, который выбирают многие программисты.

Средний уровень

? pow (сокр. power) — функция возведения в степень

pow()

Функция pow() используется для возведения числа степень. Она эквивалентна оператору возведения в степень **.

chislo, stepen = 10, 3
print(pow(chislo, stepen))  # 1000

math.pow()

math.pow() является функцией из модуля math, которая также используется для возведения числа в степень, но принимает аргументы типа float и возвращает результат типа float. В отличие от функции pow(), она не поддерживает возможность деления по модулю.

import math
chislo, stepen = 10, 3  
print(math.pow(chislo, stepen))  # 1000.0

Разница pow() и math.pow()

Казалось, бы делают они одно и то же, однако есть тонкая разница:

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() напротив оказался в полтора раза быстрее.

Продвинутый уровень

? numpy — модуль, который предоставляет общие математические и числовые операции.

Возведение в степень также является математической операцией и поддерживается данным модулем.

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]

⚠️ Важно! При работе с ОС Windows возможна ошибка.

Как мы знаем, 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 можно делать математические вычисления. Расмотрим несколько математических трюков.

Квадратный корень (√)

Корень квадратный — знакомая операция:

√9 = 3
√81 = 9

Но существует математический трюк, как посчитать корень не запоминая и не путая всякие там sqr/sqrt:

print(9 ** 0.5)  # 3.0
print(81 ** 0.5)  # 9.0

То есть степень 1/2 это корень квадратный:

√64 = 64 ** (1/2) = 8.0

Отрицательная степень

Попробуем возвести отрицательную степень:

print(7 ** -3)  # 0.0029154518950437317

Выглядит как что-то страшное. На самом деле всё довольно логично, если представить это дробью:

Формула отрицательной степени

Пример отрицательной степени:

Пример отрицательной степени

Поэтому 10-1=0.1

Нулевая степень

? Математическая база: любое число в степени 0 это 1

Пример нулевой степени в коде:

print(54532 ** 0)  # 1
print(0 ** 0)  # 1

Заключение

Возведение в степень — одна из наиболее часто используемых операций в программировании. В статье были рассмотрены три метода возведения в степень в Python: оператор **, функции pow()math.pow() и numpy.power().

Самым быстрым и универсальным способом является оператор **. Важно помнить, многое зависит от устройства и платформы, на которой пишется код. Также необходимо учитывать эффективность метода, читаемость и поддерживаемость в будущем.

Содержание
Информация была полезна?
21 оценок, среднее: 4.55 из 5