logaritmo español error domain python performance

error - sqrt python español



¿Qué es más rápido en Python: x**. 5 o math.sqrt(x)? (13)

Me he estado preguntando esto por un tiempo. Como dice el título, ¿cuál es más rápido, la función real o simplemente elevando a la mitad de potencia?

ACTUALIZAR

Esto no es una cuestión de optimización prematura. Esto es simplemente una cuestión de cómo funciona realmente el código subyacente. ¿Cuál es la teoría de cómo funciona el código Python?

Envié un correo electrónico a Guido van Rossum porque realmente quería saber las diferencias en estos métodos.

Mi email:

Hay al menos 3 formas de hacer una raíz cuadrada en Python: math.sqrt, el operador ''**'' y pow (x, .5). Solo tengo curiosidad por las diferencias en la implementación de cada uno de estos. Cuando se trata de eficiencia, ¿qué es mejor?

Su respuesta:

pow y ** son equivalentes; math.sqrt no funciona para números complejos y enlaces a la función C sqrt (). En cuanto a cuál es más rápido, no tengo ni idea ...


¿Cuántas raíces cuadradas estás realmente realizando? ¿Estás tratando de escribir un motor de gráficos 3D en Python? Si no, ¿por qué ir con código que es críptico sobre el código que es fácil de leer? La diferencia de tiempo sería menor de lo que cualquiera podría notar en casi cualquier aplicación que yo pudiera ver. Realmente no quiero dejar tu pregunta, pero parece que vas demasiado lejos con una optimización prematura.


Alguien comentó sobre la "raíz cuadrada rápida Newton-Raphson" de Quake 3 ... Lo implementé con ctypes, pero es super lento en comparación con las versiones nativas. Voy a probar algunas optimizaciones e implementaciones alternativas.

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

Aquí hay otro método que usa struct, sale aproximadamente 3.6 veces más rápido que la versión de ctypes, pero sigue siendo 1/10 la velocidad de 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


El problema que SQRMINSUM he resuelto recientemente requiere calcular la raíz cuadrada repetidamente en un gran conjunto de datos. Las dos presentaciones más antiguas de mi history , antes de realizar otras optimizaciones, difieren únicamente al reemplazar ** 0.5 con sqrt (), lo que reduce el tiempo de ejecución de 3.74 a 0.51 en PyPy. Esto es casi el doble de la ya masiva mejora del 400% que midió Claudiu.


En estos micro-puntos de referencia, math.sqrt será más lento, debido al poco tiempo que lleva buscar el sqrt en el espacio de nombres matemáticos. Puedes mejorarlo ligeramente con

from math import sqrt

Incluso entonces, ejecutando algunas variaciones a través del tiempo, muestra una ligera ventaja de rendimiento (4-5%) para "x **. 5"

Curiosamente, haciendo

import math sqrt = math.sqrt

aceleró aún más, con una diferencia de velocidad de 1%, con muy poca significación estadística.

Repetiré a Kibbee y diré que esta es probablemente una optimización prematura.


En python 2.6, la función (float).__pow__() usa la función C pow() y las funciones math.sqrt() usan la función C sqrt() .

En el compilador glibc, la implementación de pow(x,y) es bastante compleja y está bien optimizada para varios casos excepcionales. Por ejemplo, llamar a C pow(x,0.5) simplemente llama a la función sqrt() .

La diferencia en la velocidad de uso .** o math.sqrt es causada por las envolturas utilizadas alrededor de las funciones C y la velocidad depende en gran medida de los indicadores de optimización / compilador de C utilizados en el sistema.

Editar:

Aquí están los resultados del algoritmo de Claudiu en mi máquina. Tengo diferentes resultados:

zoltan@host:~$ python2.4 p.py Took 0.173994 seconds Took 0.158991 seconds zoltan@host:~$ python2.5 p.py Took 0.182321 seconds Took 0.155394 seconds zoltan@host:~$ python2.6 p.py Took 0.166766 seconds Took 0.097018 seconds



Lo más probable es math.sqrt (x), porque está optimizado para el enraizamiento cuadrado.

Benchmarks le proporcionará la respuesta que está buscando.


Lo que sería aún más rápido es si ingresas a math.py y copias la función "sqrt" en tu programa. Lleva tiempo que su programa encuentre math.py, luego ábralo, encuentre la función que está buscando y luego vuelva a traerla a su programa. Si esa función es más rápida incluso con los pasos de "búsqueda", entonces la función en sí tiene que ser terriblemente rápida. Probablemente reducirá su tiempo a la mitad. En resumen:

  1. Ve a math.py
  2. Encuentre la función "sqrt"
  3. Cópialo
  4. Pegue la función en su programa como el buscador sqrt.
  5. Cronométralo.

Los resultados de Claudiu difieren de los míos. Estoy usando Python 2.6 en Ubuntu en una vieja máquina P4 2.4Ghz ... Aquí están mis resultados:

>>> 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 seconds

sqrt es consistentemente más rápido para mí ... Incluso Codepad.org AHORA parece estar de acuerdo con que sqrt, en el contexto local, es más rápido ( http://codepad.org/6trzcM3j ). Parece que Codepad ejecuta Python 2.5 actualmente. ¿Tal vez estaban usando 2.4 o más cuando Claudiu primero respondió?

De hecho, incluso usando math.sqrt (i) en lugar de arg (i), aún obtengo mejores tiempos para sqrt. En este caso, timeit2 () tardó entre 0,53 y 0,55 segundos en mi máquina, que aún es mejor que las cifras de 0,56-0,60 de timeit1.

Yo diría, en Python moderno, usar math.sqrt y definitivamente llevarlo al contexto local, ya sea con somevar = math.sqrt o desde math import sqrt.


Por lo que vale (ver la respuesta de Jim). En mi máquina, ejecutando 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


Según los comentarios, he actualizado el código:

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()

Ahora la función math.sqrt está directamente en un argumento local, lo que significa que tiene la búsqueda más rápida posible.

ACTUALIZACIÓN: La versión de Python parece importar aquí. Solía ​​pensar que timeit1 sería más rápido, ya que cuando Python analiza "i **. 5", sabe, sintácticamente, qué método llamar ( __pow__ o alguna variante), por lo que no tiene que pasar por la sobrecarga de la búsqueda que la variante math.sqrt sí. Pero podría estar equivocado:

Python 2.5: 0.191000 vs. 0.224000

Python 2.6: 0.195000 vs. 0.139000

También psyco parece tratar mejor con math.sqrt :

Python 2.5 + Psyco 2.0: 0.109000 vs. 0.043000

Python 2.6 + Psyco 2.0: 0.128000 vs. 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: $4=100*($2-$3)/$3;%.0f

Resultados de tabla producidos en la máquina:

$ 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

Para reproducir resultados:


usando el código de Claudiu, en mi máquina incluso con "from math import sqrt" x **. 5 es más rápido pero usando psyco.full () sqrt (x) se vuelve mucho más rápido, al menos en un 200%


  • primera regla de optimización: no lo hagas
  • segunda regla: no lo hagas , aún

Aquí hay algunos tiempos (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

Esta prueba muestra que x**.5 es ligeramente más rápido que sqrt(x) .

Para Python 3.0 el resultado es el opuesto:

$ /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) siempre es más rápido que x**.5 en otra máquina (Ubuntu, Python 2.6 y 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