練習(xí):Sqrt函數(shù)可視化實(shí)現(xiàn)
本次練習(xí)主要是熟練numpy和matplotlib的使用,通過手寫Sqrt的實(shí)現(xiàn),通過可視化對(duì)比手寫函數(shù)與系統(tǒng)自帶函數(shù)之間區(qū)別。
主要實(shí)現(xiàn)思路是:牛頓法
下面簡單介紹一下牛頓法:(參考博客,參考知乎) 首先,有函數(shù)f(x) = x2,假設(shè)num是f(x)的近似值,那么num最接近f(x),就有f(x)-num=0,也就是x2 - num = 0.
那么如果畫圖,就是要求g(x)=x2 - num 與g(x)=0 的最近點(diǎn)。
極限公式:

因此有:

從幾何圖形上看,因?yàn)閷?dǎo)數(shù)是切線,通過不斷迭代,導(dǎo)數(shù)與x軸的交點(diǎn)會(huì)不斷逼近x0。

從上圖我們可以看出,第一次A點(diǎn),畫出A的切線,在X軸上有交點(diǎn),這個(gè)交點(diǎn)投影到曲線上,找到點(diǎn)B,同理,B點(diǎn)又做切線,找到一個(gè)交點(diǎn),交點(diǎn)又投影到曲線得到點(diǎn)C,逐漸接近X0。
由前面的極限公式得出:
$$f'(x_n) = \frac{dy}{dx} = \frac{f(x_n)}{x_n - x_{n+1}}$$
推導(dǎo)得出:
$$x_{n+1} = x_n -\frac{f(x_n)}{f'(x_n)}$$
ok,到這里我們舉一個(gè)實(shí)例
假設(shè)m=2,那么就有:
最終得出以下圖例:手寫的sqrt函數(shù)與系統(tǒng)自帶的基本沒有區(qū)別
、
# -*- coding:utf-8 -*-
# /usr/bin/python
import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
import math
def func(a):
if a < 1e-6: #小于0.000001,直接返回0
return 0
last = a
c = a / 2 #該值一定程度上影響迭代次數(shù)
while math.fabs(c - last) > 1e-6:#精度控制
last = c
c = (c + a/c) / 2
return c
if __name__ == '__main__':
mpl.rcParams['font.sans-serif'] = ['SimHei']
mpl.rcParams['axes.unicode_minus'] = False #保證win系統(tǒng)圖片上的中文顯示正常
x = np.linspace(0, 30, num=50) #0-30均分50份
func_ = np.frompyfunc(func, 1, 1) #轉(zhuǎn)換為ufunc函數(shù)方便使用
y_h = func_(x)
y_s = np.sqrt(x)#調(diào)用系統(tǒng)自帶函數(shù)求值
plt.figure(figsize=(10, 6), facecolor='w')#設(shè)置圖大小和背景色
plt.plot(x,y_h, 'ro-',label='手寫', lw=2, markersize=6)#(畫出x與y_h的曲線,用紅色小圓圈標(biāo)記(x,y)在圖上的位置,
#label下面legend函數(shù)要調(diào)用的,相當(dāng)于注明這條曲線的意義,lw線寬2,小圓點(diǎn)6)
plt.plot(x,y_s, 'b-',label='系統(tǒng)自帶', lw=2, markersize=6)
plt.grid(b=True, ls=':')#顯示網(wǎng)格
plt.legend(loc='lower right')#選取兩條曲線的注明所在方位
plt.xlabel('X', fontsize=16)#坐標(biāo)軸上的內(nèi)容及大小
plt.ylabel('Y', fontsize=16)
plt.title('牛頓法計(jì)算平方根', fontsize=18)
plt.show()
關(guān)于分母的取值影響迭代次數(shù)的研究
import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
import math
def func(b):
if b < 1e-6:
return 0
a = 1000
last = a
c = a / b
count = 0
while math.fabs(c - last) > 1e-6:
last = c
c = (c + a/c) / 2
count = count + 1
return count
if __name__ == '__main__':
x = np.linspace(2, 500, num=100)
func_ = np.frompyfunc(func, 1, 1)
y = func_(x)
print(x,y)
>>>[9 7 6 5 5 4 3 4 5 5 5 5 6 6 6 6 6 6 6 6 6 6 6 7 7 7 7 7 7 7 7 7 7 7 7 7 7
7 7 7 7 7 7 7 7 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8
8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 9 9 9 9 9 9 9 9 9 9]