Что быстрее в Python: x**.5 или математике.sqrt (x)?
Мне вот интересно, это в течение некоторого времени. Как говорится в названии, что быстрее, фактическая функция или просто повышение до половины мощности?
обновление
Это не вопрос преждевременной оптимизации. Это просто вопрос о том, как на самом деле работает базовый код. Какова теория того, как работает код Python?
Я послал Guido van Rossum по электронной почте, потому что я действительно хотел знать различия в этих методах.
мой электронная почта:
есть по крайней мере 3 способа сделать квадратный корень в Python: math.sqrt, the
'**'оператор и pow(x,.5). Мне просто любопытно, в чем разница
реализация каждого из них. Когда дело доходит до эффективности, которая
так лучше?
его ответ:
pow и ** эквивалентны; математика.sqrt не работает для комплексных чисел,
и ссылки на функцию C sqrt (). О что
быстрее, у меня нет идея...
13 ответов:
согласно комментариям, я обновил код:
import time import math def timeit1(): s = time.time() for i in xrange(750000): z=i**.5 print "Took %f seconds" % (time.time() - s) def timeit2(arg=math.sqrt): s = time.time() for i in xrange(750000): z=arg(i) print "Took %f seconds" % (time.time() - s) timeit1() timeit2()теперь
math.sqrtфункция находится непосредственно в локальном аргументе, что означает, что она имеет самый быстрый поиск.обновление: версия python, кажется, имеет значение здесь. Я раньше думал, что
timeit1было бы быстрее, так как когда python анализирует "i**.5 " он знает, синтаксически, какой метод вызвать (__pow__или какой-то вариант), поэтому он не должен идти через надземный поиска, чтоmath.sqrtвариант есть. Но я могу ошибаться:Python 2.5: 0.191000 против 0.224000
Python 2.6: 0.195000 против 0.139000
также psyco, кажется, имеет дело с
math.sqrtлучше:Python 2.5 + Psyco 2.0: 0,109000 против 0,043000
Python 2.6 + Psyco 2.0: 0.128000 против 0.067000
| Interpreter | x**.5, | sqrt, | sqrt faster, % | | | seconds | seconds | | |----------------+---------+---------+----------------| | Python 3.2rc1+ | 0.32 | 0.27 | 19 | | Python 3.1.2 | 0.136 | 0.088 | 55 | | Python 3.0.1 | 0.155 | 0.102 | 52 | | Python 2.7 | 0.132 | 0.079 | 67 | | Python 2.6.6 | 0.121 | 0.075 | 61 | | PyPy 1.4.1 | 0.083 | 0.0159 | 422 | | Jython 2.5.1 | 0.132 | 0.22 | -40 | | Python 2.5.5 | 0.129 | 0.125 | 3 | | Python 2.4.6 | 0.131 | 0.123 | 7 | #+TBLFM: =100*(-)/;%.0fтаблица результатов производится на машина:
$ uname -vms Linux #42-Ubuntu SMP Thu Dec 2 02:41:37 UTC 2010 x86_64 $ cat /proc/cpuinfo | grep 'model name' | head -1 model name : Intel(R) Core(TM) i7 CPU 920 @ 2.67GHzдля воспроизведения результатов:
- источник:
git clone git://gist.github.com/783011.git gist-783011- установить
tox:pip install tox- выполнить
toxв папке .
- первое правило оптимизации: не надо
- второе правило: не надо, но все же
вот некоторые тайминги (Python 2.5.2, Windows):
$ python -mtimeit -s"from math import sqrt; x = 123" "x**.5" 1000000 loops, best of 3: 0.445 usec per loop $ python -mtimeit -s"from math import sqrt; x = 123" "sqrt(x)" 1000000 loops, best of 3: 0.574 usec per loop $ python -mtimeit -s"import math; x = 123" "math.sqrt(x)" 1000000 loops, best of 3: 0.727 usec per loopэтот тест показывает, что
x**.5- это немного быстрее, чемsqrt(x).для Python 3.0 результат противоположный:
$ \Python30\python -mtimeit -s"from math import sqrt; x = 123" "x**.5" 1000000 loops, best of 3: 0.803 usec per loop $ \Python30\python -mtimeit -s"from math import sqrt; x = 123" "sqrt(x)" 1000000 loops, best of 3: 0.695 usec per loop $ \Python30\python -mtimeit -s"import math; x = 123" "math.sqrt(x)" 1000000 loops, best of 3: 0.761 usec per loop
math.sqrt(x)всегда быстрее, чемx**.5на другой машине (Ubuntu, Python 2.6 и 3.1):$ python -mtimeit -s"from math import sqrt; x = 123" "x**.5" 10000000 loops, best of 3: 0.173 usec per loop $ python -mtimeit -s"from math import sqrt; x = 123" "sqrt(x)" 10000000 loops, best of 3: 0.115 usec per loop $ python -mtimeit -s"import math; x = 123" "math.sqrt(x)" 10000000 loops, best of 3: 0.158 usec per loop $ python3.1 -mtimeit -s"from math import sqrt; x = 123" "x**.5" 10000000 loops, best of 3: 0.194 usec per loop $ python3.1 -mtimeit -s"from math import sqrt; x = 123" "sqrt(x)" 10000000 loops, best of 3: 0.123 usec per loop $ python3.1 -mtimeit -s"import math; x = 123" "math.sqrt(x)" 10000000 loops, best of 3: 0.157 usec per loop
сколько квадратных корней вы действительно выполняете? Вы пытаетесь написать какой-то 3D графический движок в Python? Если нет, то зачем идти с кодом, который является загадочным над кодом, который легко читать? Разница во времени будет меньше, чем кто-либо мог заметить в любом приложении, которое я мог бы предвидеть. Я действительно не хочу ставить ваш вопрос, но кажется, что вы заходите слишком далеко с преждевременной оптимизацией.
в этих микро-ориентиры, математика.sqrt будет медленнее из-за небольшого времени, необходимого для поиска sqrt в пространстве имен math. Вы можете немного улучшить его с
from math import sqrtдаже тогда, хотя, запустив несколько вариаций через timeit, показывают небольшое (4-5%) преимущество производительности для "x**.5"
интересно, что делал
import math sqrt = math.sqrtускорил его еще больше, в пределах 1% разницы в скорости, с очень небольшим статистическим значением.
I повторю Кибби, и скажу, что это, наверное, преждевременная оптимизация.
используя код Claudiu, на моей машине даже с "из math import sqrt" x**.5 быстрее, но с помощью psyco.full () sqrt (x) становится намного быстрее, по крайней мере на 200%
скорее всего математика.sqrt (x), потому что он оптимизирован для квадратного укоренения.
тесты предоставят вам ответ, который вы ищете.
для чего это стоит (см. ответ Джима). На моей машине работает python 2.5:
PS C:\> python -m timeit -n 100000 10000**.5 100000 loops, best of 3: 0.0543 usec per loop PS C:\> python -m timeit -n 100000 -s "import math" math.sqrt(10000) 100000 loops, best of 3: 0.162 usec per loop PS C:\> python -m timeit -n 100000 -s "from math import sqrt" sqrt(10000) 100000 loops, best of 3: 0.0541 usec per loop
кто-то прокомментировал "быстрый квадратный корень Ньютона-Рафсона" из Quake 3... Я реализовал его с помощью ctypes, но он очень медленный по сравнению с родными версиями. Я собираюсь попробовать несколько оптимизаций и альтернативных реализаций.
from ctypes import c_float, c_long, byref, POINTER, cast def sqrt(num): xhalf = 0.5*num x = c_float(num) i = cast(byref(x), POINTER(c_long)).contents.value i = c_long(0x5f375a86 - (i>>1)) x = cast(byref(i), POINTER(c_float)).contents.value x = x*(1.5-xhalf*x*x) x = x*(1.5-xhalf*x*x) return x * numвот еще один метод, использующий struct, выходит примерно на 3.6 x быстрее, чем версия ctypes, но все же 1/10 скорости C.
from struct import pack, unpack def sqrt_struct(num): xhalf = 0.5*num i = unpack('L', pack('f', 28.0))[0] i = 0x5f375a86 - (i>>1) x = unpack('f', pack('L', i))[0] x = x*(1.5-xhalf*x*x) x = x*(1.5-xhalf*x*x) return x * num
результаты Клаудиу отличаются от моих. Я использую Python 2.6 на Ubuntu на старой машине P4 2.4 Ghz... Вот мои результаты:
>>> timeit1() Took 0.564911 seconds >>> timeit2() Took 0.403087 seconds >>> timeit1() Took 0.604713 seconds >>> timeit2() Took 0.387749 seconds >>> timeit1() Took 0.587829 seconds >>> timeit2() Took 0.379381 secondssqrt последовательно быстрее для меня... Даже Codepad.org теперь, кажется, согласен, что sqrt, в локальном контексте, быстрее (http://codepad.org/6trzcM3j). Codepad, кажется, работает на Python 2.5 в настоящее время. Возможно, они использовали 2.4 или старше, когда Клаудиу первый ответил?
в самом деле, даже с помощью математики.sqrt (i) вместо arg (i), я все еще получаю лучшие времена для sqrt. В этом случае timeit2() занял от 0,53 до 0,55 секунды на моей машине, что все еще лучше, чем цифры 0,56-0,60 от timeit1.
Я бы сказал, на современном Python, используйте математику.sqrt и определенно привести его к локальному контексту, либо с somevar=math.sqrt или с помощью math import sqrt.
вы, возможно, захотите, чтобы тест быстрый квадратный корень Ньютона-Рафсона Как хорошо. Не займет много, чтобы преобразовать в Python.
проблема SQRMINSUM Я решил недавно требует вычисления квадратного корня неоднократно на большом наборе данных. Самые старые 2 представления в моем история, прежде чем я сделал другие оптимизации, отличаются только заменой **0.5 на sqrt(), тем самым уменьшая время выполнения с 3,74 С до 0,51 С в PyPy. Это почти в два раза больше, чем уже массивное улучшение 400%, которое измерил Клаудиу.
Что было бы еще быстрее, если бы вы вошли math.py и скопировал функцию "sqrt" в вашу программу. Это занимает время для вашей программы, чтобы найти math.py, затем откройте его, найдите функцию, которую вы ищете, а затем верните ее в свою программу. Если эта функция быстрее даже с шагами "поиска", то сама функция должна быть ужасно быстрой. Вероятно, сократит ваше время в два раза. Вкратце:
- перейти к math.py
- найти функцию "корень"
- скопировать
- вставить функцию в вашу программу в качестве sqrt finder.
- времени.
Comments