相比欧拉法,收敛速度更快,Quake-III中平方根倒数速算法就是基于牛顿法(解析:https://www.bilibili.com/video/av52050885/)
import sys
from bisect import bisect_left
''' 平方数表 '''
square_num = [
0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121, 144, 169, 196, 225,
256, 289, 324, 361, 400, 441, 484, 529, 576, 625, 676, 729, 784, 841,
900, 961, 1024, 1089, 1156, 1225, 1296, 1369, 1444, 1521, 1600,
1681, 1764, 1849, 1936, 2025, 2116, 2209, 2304, 2401, 2500, 2601,
2704, 2809, 2916, 3025, 3136, 3249, 3364, 3481, 3600, 3721, 3844,
3969, 4096, 4225, 4356, 4489, 4624, 4761, 4900, 5041, 5184, 5329,
5476, 5625, 5776, 5929, 6084, 6241, 6400, 6561, 6724, 6889, 7056,
7225, 7396, 7569, 7744, 7921, 8100, 8281, 8464, 8649, 8836, 9025,
9216, 9409, 9604, 9801, 10000
]
'''
f(x) = x^2 - ofst
'''
def ffx(x, ofst):
return lambda x:x * x - ofst
''' 一阶导 '''
def fx_der1(x):
return x * 2
''' 查表法快速选择初值 '''
def find_x0(target):
if target < square_num[0] or target > square_num[-1]:
return -1
return bisect_left(square_num, target)
def my_sqrt(target):
if 0 == target:
return 0.0
x = find_x0(target)
if -1 == x:
print("I will NOT calculate {}".format(target))
sys.exit(1)
fx = ffx(x, target)
rslt = float(x)
for i in range(0, 16):
# 公式
rslt = rslt - fx(rslt) / fx_der1(rslt)
return rslt
print(my_sqrt(0))
print(my_sqrt(0.1))
print(my_sqrt(1))
print(my_sqrt(1.1))
print(my_sqrt(3.1))
print(my_sqrt(10))
print(my_sqrt(9999.99))