python 微积分_《用 Python 学微积分》笔记 2
《用 Python 學(xué)微積分》原文見參考資料 1。
13、大 O 記法
比較兩個(gè)函數(shù)時(shí),我們會(huì)想知道,隨著輸入值 x 的增長或減小,兩個(gè)函數(shù)的輸出值增長或減小的速度究竟誰快誰慢。通過繪制函數(shù)圖,我們可以獲得一些客觀的感受。
比較 x!、ex、x3 和 log(x) 的變化趨勢。
importnumpy as npimportsympyimportmatplotlib.pyplot as plt
x= range(1,7)
factorial= [np.math.factorial(i) for i inx]
exponential= [np.e**i for i inx]
polynomial= [i**3 for i inx]
logarithmic= [np.log(i) for i inx]
plt.plot(x,factorial,'black',\
x,exponential,'blue',\
x,polynomial,'green',\
x,logarithmic,'red')
plt.show()
View Code
根據(jù)上圖,當(dāng) x—>∞ 時(shí),x!>ex>x3>ln(x)。要想證明的話,可以取極限,用洛必達(dá)法則,例如:
$$\lim_{x\rightarrow \infty}\frac{e^x}{x^3}=\infty$$
表明當(dāng) x—>∞ 時(shí),雖然分子分母都在趨向無窮大,但分子遠(yuǎn)遠(yuǎn)凌駕于分母之上。類似地,也可以這樣看:
$$\lim_{x\rightarrow \infty}\frac{ln(x)}{x^3}=0$$
表明分母遠(yuǎn)遠(yuǎn)凌駕于分子之上。
SymPy 是 Python 的數(shù)學(xué)符號(hào)計(jì)算庫,用它可以進(jìn)行數(shù)學(xué)公式的符號(hào)推導(dǎo)。下面代碼用 SymPy 來推導(dǎo)上面兩式。
importsympyfrom sympy.abc importx#sympy中無限infty用oo表示
print ((sympy.E**x)/(x**3)).limit(x,sympy.oo)#result is: oo
print (sympy.ln(x)/x**3).limit(x,sympy.oo)#result is 0
View Code
為了描述這種隨著 x—>∞ 或 x—>0 時(shí)函數(shù)的表現(xiàn),我們定義如下大 O 記法:
若我們稱函數(shù) f(x) 在 x—>0 時(shí)是 O(g(x)),則需要找到一個(gè)常數(shù) C,對(duì)于所有足夠小的 x,均有 |f(x)|
若我們稱函數(shù) f(x) 在 x—>∞ 時(shí)是 O(g(x)),則需要找到一個(gè)常數(shù) C,對(duì)于所有足夠大的 x,均有 |f(x)|
之所以叫大 O 記法,是因?yàn)楹瘮?shù)的增長速率很多時(shí)候被稱為函數(shù)的階(Order)。
例如,當(dāng)?x—>∞ 時(shí),x(1+x2)1/2 是 O(x2),下面來個(gè)直觀感受。
下圖是兩個(gè)函數(shù)的變化趨勢,紅線是?x(1+x2)1/2?,藍(lán)線是 2x2 。
importsympyfrom sympy.abc importximportnumpy as npimportmatplotlib.pyplot as plt
xvals= np.linspace(0,100,1000)
f= x*sympy.sqrt(1+x**2)
g= 2*x**2y1= [f.evalf(subs={x:xval}) for xval inxvals]
y2= [g.evalf(subs={x:xval}) for xval inxvals]
plt.plot(xvals[:10],y1[:10],'r',xvals[:10],y2[:10],'b')#plt.plot(xvals,y1,'r',xvals,y2,'b')
plt.show()
View Code
Sympy 可以幫助我們分析函數(shù)的階,如下面求 x(1+x2)1/2?的階。
importsympyfrom sympy.abc importx
f= x*sympy.sqrt(1+x**2)printsympy.O(f, (x, sympy.oo))#result is : O(x**2, (x, oo))
計(jì)算機(jī)中使用大 O 記法,通常是分析當(dāng)輸入數(shù)據(jù)?—>∞ 時(shí),程序在時(shí)間或空間上的表現(xiàn)。然而,從上面的介紹,我們知道這個(gè)位置可以是 0,甚至可以是任何有意義的位置。
importsympyfrom sympy.abc importx
f= x*sympy.sqrt(1+x**2)printsympy.O(f, (x, 0))#result is : O(x)
在前面泰勒級(jí)數(shù)一節(jié),利用 Sympy 取函數(shù)泰勒級(jí)數(shù)的前幾項(xiàng)時(shí),代碼是這樣:
importsympyfrom sympy.abc importx
exp= sympy.E**x
sum15= exp.series(x,0,15).removeO()print sum15
其中?removeO() 的作用是讓 sympy 忽略掉級(jí)數(shù)展開后的大 O 表示項(xiàng)。不然結(jié)果如下:
importsympyfrom sympy.abc importx
exp= sympy.E**xprint exp.series(x, 0, 3)#result is: 1 + x + x**2/2 + O(x**3)
這表示從泰勒級(jí)數(shù)的第 4 項(xiàng)起,剩余所有項(xiàng)在 x—>0 時(shí)是 O(x3)。這表明,當(dāng)?x—>0 時(shí),用 1+x+0.5x2 來近似 ex ,我們得到的誤差上限將是 Cx3,其中 C 是一個(gè)常數(shù)。也就是說,大 O 記法能用來描述我們使用多項(xiàng)式近似時(shí)的誤差。
另外大 O 記法也可以直接參與計(jì)算中去,例如要計(jì)算:
$$cos(x^2)\sqrt{(x)}$$
在 x—>0 時(shí)階 O(x5) 以內(nèi)的多項(xiàng)式近似,可以這樣:
$$cos(x^2)\sqrt{(x)}=(1-\frac{1}{2}x^4+O(x^6))x^{\frac{1}{2}}$$
$$\qquad = x^{\frac{1}{2}}- ? ?\frac{1}{2}x^{\frac{9}{2}} + O(x^{\frac{13}{2}})$$
importsympyfrom sympy.abc importxprint (sympy.cos(x**2)*sympy.sqrt(x)).series(x,0,5)#result is: sqrt(x) - x**(9/2)/2 + O(x**5)
14、導(dǎo)數(shù)
對(duì)函數(shù)某一點(diǎn)求導(dǎo),得到的是函數(shù)在該點(diǎn)處切線的斜率。選中函數(shù)圖像中某一點(diǎn),不斷放大,最后會(huì)發(fā)現(xiàn)函數(shù)圖像一條直線,這條直線就是切線。下面獲得一些直觀的感受。
import numpy asnpfromsympy.abc import x
import matplotlib.pyplotasplt
# 函數(shù)
f= x**3-2*x-6# 在x=6處正切于函數(shù)的切線
line= 106*x-438d1= np.linspace(2,10,1000)
d2= np.linspace(4,8,1000)
d3= np.linspace(5,7,1000)
d4= np.linspace(5.8,6.2,100)
domains=[d1,d2,d3,d4]
# 畫圖的函數(shù)
def makeplot(f,l,d):
plt.plot(d,[f.evalf(subs={x:xval}) for xval in d],'b',\
d,[l.evalf(subs={x:xval}) for xval in d],'r')for i inrange(len(domains)):
# 繪制包含多個(gè)子圖的圖表
plt.subplot(2, 2, i+1)
makeplot(f,line,domains[i])
plt.show()
View Code
導(dǎo)數(shù)定義 1:
$$f'(a)=\frac{df}{dx}\bigg|_{x=a}=\lim_{x\rightarrow a}\frac{f(x)-f(a)}{x-a}$$
若該極限不存在,則函數(shù)在 x=a 處的導(dǎo)數(shù)不存在。
導(dǎo)數(shù)定義 2:
$$f'(a)=\frac{df}{dx}\bigg|_{x=a}=\lim_{h\rightarrow 0}\frac{f(a+h)-f(a)}{h}$$
若該極限不存在,則函數(shù)在 x=a 處的導(dǎo)數(shù)不存在。
導(dǎo)數(shù)定義 3:
函數(shù) f(x) 在 x=a 處的導(dǎo)數(shù) f'(a) 是滿足如下條件的常數(shù) C,對(duì)于在 a 附近輸入值的微小變化 h,有 f(a+h)=f(a)+Ch+O(h2) 始終成立。也就是說導(dǎo)數(shù) C 輸入值變化中一階項(xiàng)的系數(shù)。上式稍加變化,兩邊同時(shí)除以 h,并同時(shí)取極限可得:
$$\lim_{h\rightarrow 0}\frac{f(a+h)-f(a)}{h}=\lim_{h\rightarrow 0}C+O(h)=C$$
便與上面定義 2 相一致了。
例如求 cos(x) 在 x=a 處的導(dǎo)數(shù):
$$cos(a+h)=cos(a)cos(h)-sin(a)sin(h)$$
$$\qquad = cos(a)(1+O(h^2))-sin(a)(h+O(h^3))$$
$$\qquad = cos(a)-sin(a)h +O(h^2)$$
所以:
$$\fracze8trgl8bvbq{dx}{cos(x)}\bigg|_{x=a}=-sin(a)$$
我們可以自己定義求導(dǎo)的函數(shù):
importnumpy as npfrom sympy.abc importx
f= lambda x: x**3-2*x-6
#我們?cè)O(shè)定參數(shù)h的默認(rèn)值,如果調(diào)用函數(shù)時(shí)沒有指明參數(shù)h的值,便會(huì)使用默認(rèn)值
def derivative(f,h=0.00001):return lambda x: float(f(x+h)-f(x))/h
fprime=derivative(f)print fprime(6)#result is:106.000179994
Sympy 也提供求導(dǎo)的方法:
from sympy.abc importx
f= x**3-2*x-6
printf.diff()#result is :3*x**2 - 2
print f.diff().evalf(subs={x:6})#result is : 106.0000000000
依據(jù)導(dǎo)數(shù)的定義 3,有??f(a+h)=f(a)+f'(a)h+O(h2),如果將高階項(xiàng)丟掉,就獲得了 f(a+h) 的線性近似式子:f(a+h)≈f(a)+f'(a)h。
例如,用線性近似的方法估算 2551/2:
$$\sqrt{256-1}\approx \sqrt{256}+\frac{1}{2\sqrt{256}}(-1)$$
$$\qquad = 16 - \frac{1}{32}$$
$$\qquad = 15\frac{31}{32}$$
15、牛頓迭代法
如何在不使用 x1/2 前提下求 C 的正二次根。
上述問題等價(jià)于求 f(x)=x2+C=0 的解,根據(jù)上面介紹的線性近似:f(x+h)≈f(x)+f'(x)h 。如果 f(x+h)=0,那么:
$$h\approx -\frac{f(x)}{f'(x)}$$
$$x+h\approx x - \frac{f(x)}{f'(x)}$$
如果我們對(duì) f(x)=0 的解有一個(gè)初始估計(jì) x0,便可以用上面的近似不斷獲取更加準(zhǔn)確的估計(jì)值,方法為:
$$x_{n+1} = x_{n} - \frac{f(x_n)}{f'_{x_n}}$$
將 f(x)=x2+C 代入上式,即得 xn?的更新規(guī)則:
$$x_{n+1} = \frac{1}{2}(x_{n}+\frac{C}{x_{n}})$$
from sympy.abc importxdef mysqrt(c, x = 1, maxiter = 10, prt_step =False):for i inrange(maxiter):
x= 0.5*(x+ c/x)if prt_step ==True:#在輸出時(shí),{0}和{1}將被i+1和x所替代
print "After {0} iteration, the root value is updated to {1}".format(i+1,x)returnxprint mysqrt(2,maxiter =4,prt_step =True)#After 1 iteration, the root value is updated to 1.5#After 2 iteration, the root value is updated to 1.41666666667#After 3 iteration, the root value is updated to 1.41421568627#After 4 iteration, the root value is updated to 1.41421356237#1.41421356237
通過繪圖進(jìn)一步了解這個(gè)方法,例如,我們要猜 f(x)=x2-2x-4=0 的解,從 x0=2 開始,找到 f(x) 在 x=x0 處的切線 y=2x-8,找到其與 y=0 的交點(diǎn) (4,0),將該交點(diǎn)作為新的猜測解 x1=4,如此循環(huán)。
importnumpy as npimportmatplotlib.pyplot as plt
f= lambda x: x**2-2*x-4l1= lambda x: 2*x-8l2= lambda x: 6*x-20x= np.linspace(0,5,100)
plt.plot(x,f(x),'black')
plt.plot(x[30:80],l1(x[30:80]),'blue', linestyle = '--')
plt.plot(x[66:],l2(x[66:]),'blue', linestyle = '--')
l= plt.axhline(y=0,xmin=0,xmax=1,color = 'black')
l= plt.axvline(x=2,ymin=2.0/18,ymax=6.0/18, linestyle = '--')
l= plt.axvline(x=4,ymin=6.0/18,ymax=10.0/18, linestyle = '--')
plt.text(1.9,0.5,r"$x_0$", fontsize = 18)
plt.text(3.9,-1.5,r"$x_1$", fontsize = 18)
plt.text(3.1,1.3,r"$x_2$", fontsize = 18)
plt.plot(2,0,marker = 'o', color = 'r')
plt.plot(2,-4,marker = 'o', color = 'r')
plt.plot(4,0,marker = 'o', color = 'r')
plt.plot(4,4,marker = 'o', color = 'r')
plt.plot(10.0/3,0,marker = 'o', color = 'r')
plt.show()
View Code
如下定義牛頓迭代法:
def NewTon(f, s = 1, maxiter = 100, prt_step =False):for i inrange(maxiter):#相較于f.evalf(subs={x:s}),subs()是更好的將值帶入并計(jì)算的方法。
s = s - f.subs(x,s)/f.diff().subs(x,s)if prt_step ==True:print "After {0} iteration, the solution is updated to {1}".format(i+1,s)returnsfrom sympy.abc importx
f= x**2-2*x-4
print NewTon(f, s = 2, maxiter = 4, prt_step =True)#After 1 iteration, the solution is updated to 4#After 2 iteration, the solution is updated to 10/3#After 3 iteration, the solution is updated to 68/21#After 4 iteration, the solution is updated to 3194/987#3194/987
Sympy 可以幫助我們求解方程:
importsympyfrom sympy.abc importx
f= x**2-2*x-4
printsympy.solve(f,x)#result is:[1 + sqrt(5), -sqrt(5) + 1]
參考資料:
[1] https://ryancheunggit.gitbooks.io/calculus-with-python/content/
總結(jié)
以上是生活随笔為你收集整理的python 微积分_《用 Python 学微积分》笔记 2的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 一般编译器错误_Java程序员最容易犯的
- 下一篇: python空间分析_读书笔记——《py