Show
Introduçãoo raiz quadrada de um número é uma função matemática muito comum usada em todos os aspectos da ciência – física, matemática, ciência da computação, etc. – modelando o que podemos observar com cálculo. Neste artigo, vamos dar uma olhada várias maneiras de calcular a raiz quadrada de um número em Python. Por fim, faremos um Referência de desempenho com números constantes e aleatórios, bem como listas de números aleatórios para testar todas as abordagens. Calcular raiz quadrada em Python com NumPyNumPy é uma biblioteca de computação científica, que se viu presente em muitos aplicações e casos de uso. Naturalmente, tem muitos wrappers de funções matemáticas como métodos auxiliares. Se ainda não estiver instalado, você pode instalá-lo via pip: $ pip install numpyEm termos de NumPy, o sqrt() calcula a raiz quadrada de um número e retorna o resultado: import numpy as np x = np.sqrt(2) print(x)Isto resulta em: 1.4142135623730951Além de usar uma única variável como argumento, sqrt() também é capaz de analisar listas e retornar uma lista de raízes quadradas: arr = [2, 3, 5, 7] roots = np.sqrt(arr) print(roots)Isto resulta em: [1.41421356 1.73205081 2.23606798 2.64575131]o sqrt() tem uma limitação – não pode calcular uma raiz quadrada de um número negativo, porque a operação de raiz quadrada com números reais só é definida para números positivos. Tentando inserir -4 no sqrt() resultará em uma exceção: Tentar calcular a raiz quadrada de um número negativo resultará em um aviso e um nan: RuntimeWarning: invalid value encountered in sqrt nanCalcular raiz quadrada de número complexo com NumpyFelizmente, o NumPy não está restrito a trabalhar apenas com números reais – ele também pode funcionar com números complexos: import numpy as np complex_number = -1 + 1j complex_array = [-2, 3, complex_number] complex_root = np.sqrt(complex_number) complex_array_roots = np.sqrt(complex_array) print(f"Square root of '{complex_number}':n {complex_root}") print(f"Square roots of '{complex_array}':n {complex_array_roots}")Se houver pelo menos 1 número complexo em uma lista, todos os números serão convertidos e tratados como complexos, portanto, mesmo inteiros negativos podem ser adicionados: Square root of '(-1+1j)': (0.45508986056222733+1.09868411346781j) Square roots of '[-2, 3, (-1+1j)]': [0. +1.41421356j 1.73205081+0.j 0.45508986+1.09868411j]do Python matemática Móduloo math é um módulo padrão empacotado com Python. Está sempre disponível, mas precisa ser importado e fornece wrappers para algumas funções comuns, como raiz quadrada, potências, etc: import mathmath.sqrt()o sqrt() do math é uma função direta que retorna a raiz quadrada de qualquer número positivo: print(math.sqrt(2))Isto resulta em: 1.4142135623730951Ao contrário do NumPy sqrt()ele só pode funcionar em um único elemento, então se você quiser calcular a raiz quadrada de todos os elementos em uma lista, você terá que usar um for loop ou uma compreensão de lista: import math arr = [2, 3, 5, 7] roots = [] for x in arr: roots.append(math.sqrt(x)) # OR roots = [math.sqrt(x) for x in arr]Em ambos os casos, o roots conterá: [1.4142135623730951, 1.7320508075688772, 2.23606797749979, 2.6457513110645907]math.pow()A raiz quadrada de um número também pode ser calculada elevando um número a uma potência de ½: $$sqrt x = x^{frac 1 2} $$ Então, na verdade, encontrar a raiz quadrada de um número pode ser expresso como elevar o número a uma potência de ½. math.pow() recebe dois argumentos – a base e o expoente, e eleva a base à potência de um expoente: print(math.pow(2, 0.5))Naturalmente, isso resulta em: 1.4142135623730951o ** Operadoro ** operador é um operador binário, o que significa que funciona com dois valores, assim como a multiplicação regular com * faz. No entanto, como é um operador usado para exponenciação, elevamos seu argumento esquerdo à potência de seu argumento direito. Essa abordagem pode ser usada da mesma forma que a anterior: print(2 ** 0.5)E também resulta em: o Pancada() FunçãoPython tem outro, embutido pow() método que não requer uma importação do math. Este método é tecnicamente diferente do math.pow() método internamente. math.pow() lança elementos implicitamente para duplosenquanto pow() usa a implementação interna do objeto, baseada na ** operador. Embora essa diferença na implementação possa justificar o uso de um ou outro em determinados contextos, se você estiver apenas calculando a raiz quadrada de um número, não verá a diferença: print(pow(2, 0.5))Isto resulta em: 1.4142135623730951Referência de desempenhoEntão, qual produz o melhor desempenho e qual você deve escolher? Como de costume, não há um corte claro vencedor, e depende sobre o uso dos métodos. Ou seja, se você estiver trabalhando com números constantes, números aleatórios ou uma matriz de números aleatórios em uma escala maior – esses métodos terão um desempenho diferente. Vamos testá-los todos em números constantes, números aleatórios e matrizes de números aleatórios: import timeit print("Time to execute 100k operations on constant number: n") print("math.sqrt(): %ss" % timeit.timeit("math.sqrt(100)", setup="import math", number=100000)) print("math.pow(): %ss" % timeit.timeit("math.pow(100, 0.5)", setup="import math", number=100000)) print("pow(): %ss" % timeit.timeit("pow(100, 0.5)", number=100000)) print("np.sqrt(): %ss" % timeit.timeit("np.sqrt(100)", setup="import numpy as np", number=100000)) print("** operator: %ss" % timeit.timeit("100 ** 0.5", number=100000)) print("nTime to execute 100k operations on random number: n") print("math.sqrt() %ss" % timeit.timeit("math.sqrt(random.random())", setup="import math; import random;", number=100000)) print("math.pow(): %ss" % timeit.timeit("math.pow(random.random(), 0.5)", setup="import math; import random", number=100000)) print("pow(): %ss" % timeit.timeit("pow(random.random(), 0.5)", setup="import random", number=100000)) print("np.sqrt(): %ss" % timeit.timeit("np.sqrt(random.random())", setup="import numpy as np; import random", number=100000)) print("** operator: %ss" % timeit.timeit("random.random() ** 0.5", setup="import random", number=100000)) print("nTime to execute 100k operations on list of random numbers: n") print("math.sqrt() %ss" % timeit.timeit("[math.sqrt(x) for x in np.random.rand(100)]", setup="import math; import numpy as np;", number=100000)) print("math.pow(): %ss" % timeit.timeit("[math.pow(x, 0.5) for x in np.random.rand(100)]", setup="import math; import numpy as np;", number=100000)) print("pow(): %ss" % timeit.timeit("[pow(x, 0.5) for x in np.random.rand(100)]", setup="import numpy as np;", number=100000)) print("np.sqrt(): %ss" % timeit.timeit("np.sqrt(np.random.rand(100))", setup="import numpy as np; import numpy as np;", number=100000)) print("** operator: %ss" % timeit.timeit("np.random.rand(100) ** 0.5", setup="import numpy as np", number=100000))Passamos todos os métodos descritos acima pelo mesmo teste – um número constante (que provavelmente será armazenado em cache para otimização), um número aleatório em cada uma das 100 mil iterações e um Lista de 100 números aleatórios.
Observação: Apenas os números relativos em cada teste em comparação com outros métodos nesse teste são relevantes, pois leva mais tempo para gerar 100 números aleatórios do que usar o valor constante (em cache). A execução deste trecho de código resulta em: Com números constantes – o math.pow(), math.sqrt() e pow()s superam significativamente o NumPy sqrt()pois eles podem utilizar melhor o cache na CPU no nível do idioma. Com números aleatórios, o cache não funciona também e vemos discrepâncias menores. Com listas de números aleatórios, np.sqrt() supera todos os três métodos integrados significativamentee as ** operador atua no mesmo estádio. Para resumir:
Dependendo da entrada concreta com a qual você está lidando – você escolherá entre essas funções. Embora possa parecer que eles vão tudo tenha um bom desempenho, e enquanto estiver em a maioria casos, não fará muita diferença, ao lidar com grandes conjuntos de dados, até mesmo uma redução de 10% no tempo de processamento pode ajudar a longo prazo. Dependendo dos dados que você está processando – test the different approaches on your local machine. ConclusãoNeste pequeno artigo, examinamos várias maneiras de calcular o Raiz quadrada de um número em Python. Demos uma olhada no mathde pow() e sqrt()s, bem como o built-in pow()NumPy’s sqrt() e a ** operador. Por fim, comparamos os métodos para comparar seu desempenho em diferentes tipos de entrada – números constantes, números aleatórios e listas de números aleatórios. |