Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

170
Views
¿Por qué math.sqrt es masivamente más lento que la exponenciación?

No puedo creer lo que acabo de medir:

 python3 -m timeit -s "from math import sqrt" "sqrt(2)" 5000000 loops, best of 5: 42.8 nsec per loop python3 -m timeit "2 ** 0.5" 50000000 loops, best of 5: 4.93 nsec per loop

Esto va en contra de cualquier intuición... ¡debería ser exactamente lo contrario!

Python 3.8.3 en macOS Catalina

over 4 years ago · Santiago Trujillo
3 answers
Answer question

0

Python 3 calcula previamente el valor de 2 ** 0.5 en tiempo de compilación, ya que ambos operandos se conocen en ese momento. Sin embargo, el valor de sqrt no se conoce en tiempo de compilación, por lo que el cálculo necesariamente ocurre en tiempo de ejecución.

No está midiendo cuánto tiempo lleva calcular 2 ** 0.5 , sino solo el tiempo que lleva cargar una constante.

Una comparación más justa sería

 $ python3 -m timeit -s "from math import sqrt" "sqrt(2)" 5000000 loops, best of 5: 50.7 nsec per loop $ python3 -m timeit -s "x = 2" "x**0.5" 5000000 loops, best of 5: 56.7 nsec per loop

No estoy seguro de si hay una forma de mostrar el código de bytes no optimizado. Python comienza analizando el código fuente en un árbol de sintaxis abstracta (AST):

 >>> ast.dump(ast.parse("2**0.5")) 'Module(body=[Expr(value=BinOp(left=Num(n=2), op=Pow(), right=Num(n=0.5)))])'

Actualización : esta optimización particular ahora se aplica directamente al árbol de sintaxis abstracta , por lo que el código de bytes se genera directamente desde algo como

 Module(body=Num(n= 1.4142135623730951))

El módulo ast no parece aplicar la optimización.

El compilador toma el AST y genera un código de bytes no optimizado; en este caso, creo que se vería (según la salida de dis.dis("2**x") y dis.dis("x**0.5") ) como

 LOAD_CONST 0 (2) LOAD_CONST 1 (0.5) BINARY_POWER RETURN_VALUE

El código de bytes sin procesar está sujeto a modificaciones por parte del optimizador de mirilla, que puede reducir estas 4 instrucciones a 2, como se muestra en el módulo dis .

Luego, el compilador genera un código de bytes a partir del AST.

 >>> dis.dis("2**0.5") 1 0 LOAD_CONST 0 (1.4142135623730951) 2 RETURN_VALUE

[Si bien el siguiente párrafo se escribió originalmente con la idea de optimizar el código de bytes en mente, el razonamiento también se aplica a la optimización del AST].

Dado que nada en el tiempo de ejecución afecta cómo se evalúan las dos LOAD_CONST y BINARY_POWER (por ejemplo, no hay búsquedas de nombres), el optimizador de mirilla puede tomar esta secuencia de códigos de bytes, realizar el cálculo de 2**0.5 y reemplazar el primeras tres instrucciones con una sola instrucción LOAD_CONST que carga el resultado inmediatamente.

over 4 years ago · Santiago Trujillo Report

0

Para mejorar la respuesta de Chepner , aquí hay una prueba:

 Python 3.5.3 (default, Sep 27 2018, 17:25:39) [GCC 6.3.0 20170516] on linux Type "help", "copyright", "credits" or "license" for more information. >>> import dis >>> dis.dis('2 ** 0.5') 1 0 LOAD_CONST 2 (1.4142135623730951) 3 RETURN_VALUE

contra

 >>> dis.dis('sqrt(2)') 1 0 LOAD_NAME 0 (sqrt) 3 LOAD_CONST 0 (2) 6 CALL_FUNCTION 1 (1 positional, 0 keyword pair) 9 RETURN_VALUE
over 4 years ago · Santiago Trujillo Report

0

>>> dis.dis('44442.3123 ** 0.5') 0 LOAD_CONST 0 (210.81345379268373) 2 RETURN_VALUE

No creo que 44442.3123 ** 0.5 esté precalculado en tiempo de compilación. Deberíamos comprobar mejor el AST del código.

 >>> import ast >>> import math >>> code = ast.parse("2**2") >>> ast.dump(code) 'Module(body=[Expr(value=BinOp(left=Num(n=2), op=Pow(), right=Num(n=2)))])' >>> code = ast.parse("math.sqrt(3)") >>> ast.dump(code) "Module(body=[Expr(value=Call(func=Attribute(value=Name(id='math', ctx=Load()), attr='sqrt', ctx=Load()), args=[Num(n=3)], keywords=[]))])"
over 4 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!