• Empleos
  • Sobre nosotros
  • profesionales
    • Inicio
    • Empleos
    • Cursos y retos
    • Preguntas
    • Profesores
  • empresas
    • Inicio
    • Publicar vacante
    • Nuestro proceso
    • Precios
    • Pruebas Online
    • Nómina
    • Blog
    • Comercial
    • Calculadora de salario

0

256
Vistas
¿Cuál es la forma más rápida de calcular/crear potencias de diez?

Si como entrada proporciona la potencia (entera), ¿cuál es la forma más rápida de crear la potencia de diez correspondiente? Aquí hay cuatro alternativas que se me ocurren, y la forma más rápida parece ser usando una cuerda f:

 from functools import partial from time import time import numpy as np def fstring(power): return float(f'1e{power}') def asterisk(power): return 10**power methods = { 'fstring': fstring, 'asterisk': asterisk, 'pow': partial(pow, 10), 'np.pow': partial(np.power, 10, dtype=float) } # "dtype=float" is necessary because otherwise it will raise: # ValueError: Integers to negative integer powers are not allowed. # see https://stackoverflow.com/a/43287598/5472354 powers = [int(i) for i in np.arange(-10000, 10000)] for name, method in methods.items(): start = time() for i in powers: method(i) print(f'{name}: {time() - start}')

Resultados:

 fstring: 0.008975982666015625 asterisk: 0.5190775394439697 pow: 0.4863283634185791 np.pow: 0.046906232833862305

Supongo que el método f-string es el más rápido porque en realidad no se calcula nada, aunque solo funciona para potencias enteras de diez, mientras que los otros métodos son operaciones más complicadas que también funcionan con cualquier número real como base y potencia. Entonces, ¿el f-string es realmente la mejor manera de hacerlo?

about 3 years ago · Santiago Trujillo
3 Respuestas
Responde la pregunta

0

Estás comparando manzanas con naranjas aquí. 10 ** n calcula un número entero (cuando n no es negativo), mientras que float(f'1e{n}') calcula un número de coma flotante. Esos no tomarán la misma cantidad de tiempo, pero resuelven diferentes problemas, por lo que no importa cuál sea más rápido.

Pero es peor que eso, porque existe la sobrecarga de llamar a una función, que está incluida en su tiempo para todas sus alternativas, pero solo algunas de ellas realmente implican llamar a una función. Si escribe 10 ** n , entonces no está llamando a una función, pero si usa partial(pow, 10) entonces debe llamarlo como una función para obtener un resultado. Entonces, en realidad no estás comparando la velocidad de 10 ** n de manera justa.

En lugar de ejecutar su propio código de tiempo, use la biblioteca timeit , que está diseñada para hacer esto correctamente. Los resultados están en segundos para 1,000,000 de repeticiones (por defecto), o de manera equivalente, son el tiempo promedio en microsegundos para una repetición.

Aquí hay una comparación para calcular potencias enteras de 10:

 >>> from timeit import timeit >>> timeit('10 ** n', setup='n = 500') 1.09881673199925 >>> timeit('pow(10, n)', setup='n = 500') 1.1821871869997267 >>> timeit('f(n)', setup='n = 500; from functools import partial; f = partial(pow, 10)') 1.1401332350014854

Y aquí hay una comparación para calcular potencias de punto flotante de 10: tenga en cuenta que calcular 10.0 ** 500 o 1e500 tiene sentido porque el resultado es simplemente un OverflowError o inf .

 >>> timeit('10.0 ** n', setup='n = 200') 0.12391662099980749 >>> timeit('pow(10.0, n)', setup='n = 200') 0.17336435099969094 >>> timeit('f(n)', setup='n = 200; from functools import partial; f = partial(pow, 10.0)') 0.18887039500077663 >>> timeit('float(f"1e{n}")', setup='n = 200') 0.44305286100097874 >>> timeit('np.power(10.0, n, dtype=float)', setup='n = 200; import numpy as np') 1.491982370000187 >>> timeit('f(n)', setup='n = 200; from functools import partial; import numpy as np; f = partial(np.power, 10.0, dtype=float)') 1.6273324920002779

Entonces, la más rápida de estas opciones en ambos casos es la obvia: 10 ** n para números enteros y 10.0 ** n para flotantes.

about 3 years ago · Santiago Trujillo Denunciar

0

Otro contendiente para el caso de los flotadores, calcule previamente todos los posibles resultados finitos distintos de cero y búsquelos:

 0.0 if n < -323 else f[n] if n < 309 else inf

La preparación:

 f = [10.0 ** i for i in [*range(309), *range(-323, 0)]] inf = float('inf')

Punto de referencia con el exponente de kaya3 n = 200 , así como n = -200 como exponente negativo con resultado distinto de cero y n = -5000 / n = 5000 como exponentes negativos/positivos de tamaño mediano de su rango original:

 n = 200 487 ns 487 ns 488 ns float(f'1e{n}') 108 ns 108 ns 108 ns 10.0 ** n 128 ns 129 ns 130 ns 10.0 ** n if n < 309 else inf 72 ns 73 ns 73 ns 0.0 if n < -323 else f[n] if n < 309 else inf n = -200 542 ns 544 ns 545 ns float(f'1e{n}') 109 ns 109 ns 110 ns 10.0 ** n 130 ns 130 ns 131 ns 10.0 ** n if n < 309 else inf 76 ns 76 ns 76 ns 0.0 if n < -323 else f[n] if n < 309 else inf n = -5000 291 ns 291 ns 291 ns float(f'1e{n}') 99 ns 99 ns 100 ns 10.0 ** n 119 ns 120 ns 120 ns 10.0 ** n if n < 309 else inf 34 ns 34 ns 34 ns 0.0 if n < -323 else f[n] if n < 309 else inf n = 5000 292 ns 293 ns 293 ns float(f'1e{n}') error error error 10.0 ** n 33 ns 33 ns 33 ns 10.0 ** n if n < 309 else inf 53 ns 53 ns 53 ns 0.0 if n < -323 else f[n] if n < 309 else inf

Código de referencia ( ¡Pruébelo en línea! ):

 from timeit import repeat solutions = [ "float(f'1e{n}')", '10.0 ** n', '10.0 ** n if n < 309 else inf', '0.0 if n < -323 else f[n] if n < 309 else inf', ] for n in 200, -200, -5000, 5000: print(f'{n = }') setup = f''' n = {n} f = [10.0 ** i for i in [*range(309), *range(-323, 0)]] inf = float('inf') ''' for solution in solutions: try: ts = sorted(repeat(solution, setup))[:3] except OverflowError: ts = [None] * 3 print(*('%3d ns ' % (t * 1e3) if t else ' error ' for t in ts), solution) print()
about 3 years ago · Santiago Trujillo Denunciar

0

Puede intentarlo con un enfoque logarítmico usando math.log y math.exp pero el rango de valores será limitado (que puede manejar con try/except).

Esto parece ser tan rápido como fstring, si no un poco más rápido.

 import math ln10 = math.log(10) def mPow(power): try: return math.exp(ln10*power) except: return 0 if power<0 else math.inf

[EDITAR] Dado que estamos limitados por las capacidades de los flotadores, también podríamos preparar una lista con las 617 posibles potencias de 10 (que se pueden mantener en un flotador) y obtener la respuesta por índice:

 import math minP10,maxP10 = -308,308 powersOf10 = [10**i for i in range(maxP10+1)]+[10**i for i in range(minP10,0)] def tenPower(power): if power < minP10: return 0 if power > maxP10: return math.inf return powersOf10[power] # negative indexes for powers -308...-1

Este es definitivamente más rápido que fstring

about 3 years ago · Santiago Trujillo Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Nuestro proceso Comercial
Legal
Términos y condiciones Política de privacidad
© 2025 PeakU Inc. All Rights Reserved.

Andres GPT

Recomiéndame algunas ofertas
Necesito ayuda