Как выполнить квадратный корень без использования математического модуля?
Я хочу найти квадратный корень из числа без использования математического модуля, так как мне нужно вызвать функцию примерно 20k раз и не хочу замедлять выполнение, связываясь с математическим модулем каждый раз, когда функция вызывается
Есть ли более быстрый и простой способ поиска квадратного корня?
Ответы
Ответ 1
Импорт математического модуля происходит только один раз, и вы, вероятно, не получите гораздо быстрее, чем математический модуль. Существует также более старый вопрос о Stackoverflow относительно который быстрее в Python: x **. 5 или math.sqrt(x)?. Неясно, какой метод выполняется быстрее.
Возможно, посмотрите NumPy и SciPy, не обязательно для sqrt, но если вы делаете тяжелые вычисления, они могут быть удобными.
Ответ 2
Как сказал Фабиан, трудно быть быстрее, чем math.sqrt
. Причина в том, что он вызывает функцию соответствия из библиотеки C, с CPython.
Однако вы можете ускорить процесс, удалив служебные данные поиска атрибутов:
from math import sqrt
Каждый последующий вызов sqrt не должен искать его в математическом модуле, что экономит время выполнения:
print sqrt(2)
Здесь приведены временные номера: от самого быстрого до самого медленного (Python 2.6.5, Mac OS X 10.6.3): sqrt
быстрее, чем **0.5
:
[email protected] ~ % python -m timeit -s 'from math import sqrt; x = 2' 'sqrt(x)'
1000000 loops, best of 3: 0.207 usec per loop
[email protected] ~ % python -m timeit -s 'x = 2' 'x**0.5'
1000000 loops, best of 3: 0.226 usec per loop
[email protected] ~ % python -m timeit -s 'import math; x = 2' 'math.sqrt(x)'
1000000 loops, best of 3: 0.268 usec per loop
Обратите внимание, что тесты времени вычисляют квадратный корень переменной. Они не вычисляют константу как 2**0.5
, потому что 2**0.5
предварительно вычисляется в CPython:
import dis
def f():
return 2**0.5
print dis.dis(f)
печатает
2 0 LOAD_CONST 3 (1.4142135623730951)
3 RETURN_VALUE
где вы видите константу float sqrt (2) = 1.414...
Если вы манипулируете массивами чисел, NumPy sqrt
- это путь, как указано в другом ответе.
Ответ 3
Я думаю, что математическая библиотека, вероятно, будет так же быстро, как и все, что вы могли бы написать сами. Но если вы хотите написать свой собственный, вот один алгоритм. Я не знаю Python, поэтому я просто напишу какой-нибудь псевдокод.
function sqrt(x)
lastGuess=x/2
loop
guess=(lastGuess+x/lastGuess)/2
if abs(guess-lastGuess)<.000001 // or whatever threshold you want
exit loop
lastGuess=guess
return guess
и псевдокод, переведенный на Python:
def sqrt(x):
last_guess= x/2.0
while True:
guess= (last_guess + x/last_guess)/2
if abs(guess - last_guess) < .000001: # example threshold
return guess
last_guess= guess
Ответ 4
В некоторых особых случаях вы можете торговать размером программы для скорости вздутия. Создайте большой массив и сохраните предварительно рассчитанный результат для каждой операции с квадратным корнем (используя входное значение в качестве индекса). Это довольно ограничено, но вы не получите ничего быстрее.
(Это как землетрясение)
Ответ 5
Вы можете реализовать метод Newton, но, хотя он очень быстро, он вряд ли будет быстрее, чем версия C, которую я предполагаю, реализована в математическом модуле. См. http://en.wikipedia.org/wiki/Methods_of_computing_square_roots.
Ответ 6
Используйте оператор питания и поднимите свои цифры на 1/2 мощности:
>>> 2**0.5
1.4142135623730951
Что происходит быстрее:
>>> timeit.timeit(stmt='sqrt(x)', setup='from math import sqrt; x = 2')
0.7182440785071833
>>> timeit.timeit(stmt='x**0.5', setup='from math import sqrt; x = 2')
0.87514279049432275
Ответ 7
Фрагмент кода Python для вычисления квадрата. Сначала он делает предварительную догадку, и если догадка не достаточно хороша, она повторяется до тех пор, пока мы не получим хорошее предположение
def gen_square_root_v1(number, epsilon):
#boundary condition check
if number == '1':
return 1
elif number <= 0:
print('this computes square root for positive numbers only' )
else:
pass
prev_estimate = number/2
while True:
#each itearation, calculate a new estimate
new_estimate = (prev_estimate + number/prev_estimate)/2
#Alternatively can use if abs(new_estimate - prev_estimate) < epsilon:
#check the difference between square of new_estimate and number
if abs(new_estimate * new_estimate - number) < epsilon:
return prev_estimate
#if guess is not good enough, use it to make the next guess
prev_estimate = new_estimate
#call the function
print(gen_square_root_v1(16,1e-5))