* vs ** для операции степени 2

Поэтому я постоянно вижу, как люди пишут код, и когда они хотят увидеть версию заданного значения в квадрате, они пишут x*x вместо x**2. Есть ли такое большое совпадение эффективности между этими двумя точками, что данная функция в питоне не просто используется, или это просто стилистическая точка? Я бы предпочел использовать оператор **, но если это приведет к огромной ошибке, должен ли я выполнять операцию миллиард раз, я знаю, что это слишком, я хотел бы знать. Кроме того, если я ошибаюсь в порядке величины операций, которые одна берет на себя другой, я также хотел бы, чтобы меня поправили. т.е. если ** более эффективен, чем x*x, то я также хотел бы знать, почему.


person L.P.    schedule 17.10.2015    source источник
comment
Я предполагаю, что люди используют x*x вместо x**2, потому что это работает на всех языках, тогда как x**2 не работает в Java/C/C++. Поэтому я предполагаю, что причина в незнании большинства примеров. Мне любопытно узнать, есть ли разница в эффективности / числовая разница.   -  person Martin Thoma    schedule 17.10.2015


Ответы (2)


Я не согласен с g.d.d.c, умножение намного быстрее!

"""Evaluating the difference in execution time between n*n and n**2"""

from time import time

n = 2
t = time()
for i in range(5000000):
    n**2
print("Time for n**2:\t%0.3f" % (time()-t))
t = time()
for i in range(5000000):
    n*n
print("Time for n*n:\t%0.3f" % (time()-t))


def test(n):
    """
    Difference in execution time between n*n and n**2
    within function scope.
    """
    t = time()
    for i in range(5000000):
        n**2
    print("Time for n**2:\t%0.3f" % (time()-t))
    t = time()
    for i in range(5000000):
        n*n
    print("Time for n*n:\t%0.3f" % (time()-t))

test(n)

Результаты :

Time for n**2: 2.324496030807495
Time for n*n:  0.5879969596862793
Time for n**2: 2.0771241188049316
Time for n*n:  0.2894318103790283

Вы можете видеть, что умножение выполняется примерно в 4 раза быстрее вне функции и в 7 раз быстрее в функции. Я не могу объяснить разницу между этими двумя тестами, и я не уверен в разнице между n*n и n**2, но это может быть связано с тем, что Python является интерпретируемым языком, и обработка последнего занимает больше времени, даже если операции процессора очень похожи, как показывает gddc.

person Labo    schedule 17.10.2015
comment
Почему это имеет значение (и такое огромное!) если оно находится в функции или вне функции? - person Martin Thoma; 17.10.2015
comment
@moose: Скорее всего, потому что поиск глобальной переменной - это поиск по словарю, а поиск локальной переменной - индексация в массив. - person user2357112 supports Monica; 17.10.2015
comment
Теперь я немного запутался, я вижу, что на самом деле он учитывает огромную разницу в скорости, которая как бы обозначает мою начальную точку. Я не думал, что это будет такая большая разница, или что это вызовет различие между тем, чтобы быть в рамках функции или вне ее. Такой странный язык иногда. - person L.P.; 17.10.2015
comment
@ user2357112 то, что вы говорите, очень интересно, не могли бы вы объяснить подробнее, пожалуйста? Я думал, что locals() возвращает dict так же, как и globals()… - person Labo; 17.10.2015
comment
Кроме того, похоже, что вы рассчитали это на Python 3, в то время как другой парень рассчитал время на Python 2. Возведение в степень в Python 3 работает намного хуже, чем возведение в степень в Python 2 для этого случая; на Python 2 тайминги для n**2 и n*n почти идентичны, как и в другом ответе. - person user2357112 supports Monica; 17.10.2015
comment
@Labo: locals() возвращает словарь, но Python на самом деле не использует словарь для поиска локальных переменных. Это одна из причин, по которой в документах не рекомендуется изменять dict; это не повлияет на значения локальных переменных. - person user2357112 supports Monica; 17.10.2015
comment
Кстати, какая у вас версия Python 3? Мой тест на ideone, для которого Python 3 является Python 3.4, показал существенное улучшение производительности возведения в степень по сравнению с умножением. - person user2357112 supports Monica; 17.10.2015
comment
Python 3.4.3, но 3 или 4 почти одинаковы… - person Labo; 17.10.2015
comment
+1 за код; но вы также должны провести эксперимент с переключением: просто поменяйте местами блоки кода n*n и n**2. Особенно для глобального эксперимента вы заметите, что это имеет значение. - person Martin Thoma; 18.10.2015

На самом деле, они, вероятно, очень похожи по общей стоимости:

>>> def s1(x):
...   return x * x
...
>>>
>>> def s2(x):
...   return x ** 2
...
>>>
>>> from dis import dis
>>>
>>> dis(s1)
  2           0 LOAD_FAST                0 (x)
              3 LOAD_FAST                0 (x)
              6 BINARY_MULTIPLY
              7 RETURN_VALUE
>>> dis(s2)
  2           0 LOAD_FAST                0 (x)
              3 LOAD_CONST               1 (2)
              6 BINARY_POWER
              7 RETURN_VALUE
>>>

Я думаю, что вы, вероятно, преждевременно оптимизируете, даже для миллионов или миллиардов итераций. Если вы не определили это как узкое место, просто используйте то, что для вас наиболее идиоматично.

И, для полноты, результаты timeit:

>>> timeit.Timer("s1(10)", 'from __main__ import s1').timeit(100000)
0.0186597650628606
>>> timeit.Timer("s2(10)", 'from __main__ import s2').timeit(100000)
0.018789616358585448

Что, по-видимому, показывает, что x * x чуть-чуть быстрее в 100 000 итераций.

person g.d.d.c    schedule 17.10.2015
comment
Так что это само по себе просто концепция стиля. Я всегда думал, что это было что-то вроде функции pow() в c, поскольку она вызывала функцию, которую я видел в этом языке, но в python, поскольку она встроена. Я просто не понимаю, почему бы и нет. использовать его. На мой взгляд, это немного более выразительно, чем другие, если оператор известен и понятен. Но спасибо за этот фрагмент. - person L.P.; 17.10.2015
comment
Для 10e6 это именно то значение, но будет ли оно расти экспоненциально во времени или постоянно? Я знаю, что по большому счету это имело бы чуть меньшее значение, но выполнение задач проекта Эйлера, чтобы выучить язык Python, и время, даже четверть секунды, немного меня раздражает. - person L.P.; 17.10.2015
comment
Неа. Возведение в степень намного медленнее, чем умножение на обычных процессорах. Ваш тест этого не показывает, потому что во времени преобладает стоимость вызова функции (я предполагаю) или другие динамические махинации Python. В компилируемых языках разница существенна. Даже в Python я мог представить, что это будет иметь большое значение в тесном цикле без вызова функции, но я не проводил бенчмаркинга. В любом случае, это (к сожалению) далеко не преждевременная оптимизация для многих приложений. - person Konrad Rudolph; 17.10.2015
comment
@KonradRudolph: Дело не в процессоре; Возведение в степень Python int не вызывает никаких инструкций по возведению в степень ЦП. Это все программное обеспечение. В Python 2, даже если вы исключите вызов функции, разница составит около 6% из-за всех остальных накладных расходов; в Python 3 разница примерно в 3 раза, так как код возведения в степень bignum не обрабатывает вещи как Что ж. - person user2357112 supports Monica; 17.10.2015
comment
@user2357112 user2357112 Не понимаю, как это улучшит ситуацию. Внедрение возведения в степень в программном обеспечении сделало бы это еще медленнее по сравнению с умножением. Ваш тест недостаточен, чтобы показать эту разницу, потому что операции слишком быстрые, а точность таймера сравнительно низкая. - person Konrad Rudolph; 17.10.2015