Использование мощного оператора **
будет быстрее, так как у него не будет накладных расходов на вызов функции. Это можно увидеть, если разобрать код Python:
>>> dis.dis('7. ** i')
1 0 LOAD_CONST 0 (7.0)
3 LOAD_NAME 0 (i)
6 BINARY_POWER
7 RETURN_VALUE
>>> dis.dis('pow(7., i)')
1 0 LOAD_NAME 0 (pow)
3 LOAD_CONST 0 (7.0)
6 LOAD_NAME 1 (i)
9 CALL_FUNCTION 2 (2 positional, 0 keyword pair)
12 RETURN_VALUE
>>> dis.dis('math.pow(7, i)')
1 0 LOAD_NAME 0 (math)
3 LOAD_ATTR 1 (pow)
6 LOAD_CONST 0 (7)
9 LOAD_NAME 2 (i)
12 CALL_FUNCTION 2 (2 positional, 0 keyword pair)
15 RETURN_VALUE
Обратите внимание, что здесь я использую переменную i
в качестве экспоненты, потому что константные выражения, такие как 7. ** 5
, фактически оцениваются во время компиляции.
Теперь, на практике, эта разница не имеет большого значения, как вы можете видеть, рассчитывая время:
>>> from timeit import timeit
>>> timeit('7. ** i', setup='i = 5')
0.2894785532627111
>>> timeit('pow(7., i)', setup='i = 5')
0.41218495570683444
>>> timeit('math.pow(7, i)', setup='import math; i = 5')
0.5655053168791255
Таким образом, хотя pow
и math.pow
примерно в два раза медленнее, они все еще достаточно быстры, чтобы не обращать на них особого внимания. Если вы не можете фактически определить возведение в степень как узкое место, не будет причин выбирать один метод вместо другого, если ясность ухудшится. Это особенно актуально, поскольку pow
предлагает, например, интегрированную операцию по модулю.
Alfe задал хороший вопрос в комментариях выше:
timeit
показывает, что math.pow
медленнее, чем **
во всех случаях. На что вообще годен math.pow()
? Кто-нибудь знает, где это может быть выгодно?
Большое отличие math.pow
как от встроенного pow
, так и от мощного оператора **
заключается в том, что он всегда использует семантику с плавающей запятой. Поэтому, если вы по какой-то причине хотите убедиться, что в результате получите число с плавающей запятой, то math.pow
обеспечит это свойство.
Давайте рассмотрим пример: у нас есть два числа, i
и j
, и мы понятия не имеем, являются ли они числами с плавающей запятой или целыми числами. Но мы хотим получить результат с плавающей запятой i^j
. Итак, какие варианты у нас есть?
- Мы можем преобразовать хотя бы один из аргументов в число с плавающей запятой, а затем выполнить
i ** j
.
- Мы можем сделать
i ** j
и преобразовать результат в число с плавающей запятой (возведение в степень с плавающей запятой автоматически используется, когда i
или j
являются числами с плавающей запятой, поэтому результат будет таким же).
- Мы можем использовать
math.pow
.
Итак, давайте проверим это:
>>> timeit('float(i) ** j', setup='i, j = 7, 5')
0.7610865891750791
>>> timeit('i ** float(j)', setup='i, j = 7, 5')
0.7930400942188385
>>> timeit('float(i ** j)', setup='i, j = 7, 5')
0.8946636625872202
>>> timeit('math.pow(i, j)', setup='import math; i, j = 7, 5')
0.5699394063529439
Как видите, math.pow
на самом деле быстрее! И если подумать, накладные расходы на вызов функции теперь также исчезли, потому что во всех других альтернативах мы должны вызывать float()
.
Кроме того, стоит отметить, что поведение **
и pow
можно переопределить, реализуя специальный метод __pow__
(и __rpow__
) для пользовательских типов. Так что, если вы этого не хотите (по какой-либо причине), использование math.pow
этого не сделает.
person
poke
schedule
07.01.2014
timeit
узнать? - person mgilson   schedule 07.01.2014timeit
показывает, чтоmath.pow
медленнее, чем**
во всех случаях. На что вообще годитсяmath.pow()
? Кто-нибудь знает, где это может быть выгодно? - person Alfe   schedule 07.01.2014in all cases
? Я вижу случаи, когдаmath.pow
намного быстрее. - person Wolf   schedule 16.02.2015pow
сmath.pow
, но я говорю о сравненииmath.pow
с оператором**
. Ваше сравнение может быть завершено добавлением этой третьей версии, тогда**
снова превосходит любой другой вариант:import timeit; print timeit.timeit("math.pow(2, 100)",setup='import math'), timeit.timeit("pow(2, 100)"), timeit.timeit("2 ** 100")
→0.170357942581 1.00546097755 0.013473033905
. - person Alfe   schedule 17.02.2015math.pow
всегда возвращаетfloat
(также для вводаint
), а**
возвращает тип своего ввода (ну, смешанный ввод приводит кfloat
). Но это все еще не повод использоватьmath.pow
, ИМХО. - person Alfe   schedule 17.02.2015What is math.pow() good for anyway?
), похоже, еще не получил ответа. В любом случае, большое спасибо за ваше время :-) - person Wolf   schedule 17.02.20154926601444670 ** 4235309647073 % 6000029000033
вызывает сбой интерпретатора,pow(4926601444670 , 4235309647073, 6000029000033)
происходит мгновенно. - person temporary_user_name   schedule 01.05.2016