程序?qū)崿F(xiàn)黎曼和(定積分)

想象一下屁使,如果你手里有一塊形狀不規(guī)則的土地(實際上我沒有,窮...)荚藻,要測量它的面積屋灌,怎么辦呢?

拿尺子量应狱,不知如何下手共郭,突然感覺高中幾何解決不了,得祭出本科的高等數(shù)學(xué)才行疾呻。所以除嘹,慣例我們應(yīng)該發(fā)揚拿來主義,比如 “國際上岸蜗,如何如何...”:

一個叫黎曼的德國數(shù)學(xué)家(Bernhard Riemann, 1826-1866)尉咕,他想了個辦法:將這不規(guī)則圖形切成一條條的小長條兒,然后將這個長條近似的看成一個矩形璃岳,再分別測量出這些小矩形的長度年缎,再計算出它們的面積,把所有矩型面積加起來就是這塊不規(guī)則地的面積铃慷。這就是著名的“黎曼和”单芜。小長條寬度趨于0時,即為面積微分犁柜,各個面積求和取極限即為定積分洲鸠。雖然牛頓時代就給出了定積分的定義,但是定積分的現(xiàn)代數(shù)學(xué)定義卻是用黎曼和的極限給出。

好吧扒腕,大致意思是理解了绢淀,光說不行,得練習(xí)瘾腰。于是我先造出來一塊地來當(dāng)?shù)刂鹘缘模彤?dāng)下圖綠色部分是我的地吧


image.png

誰家能把土地劃成這樣啊,好吧居灯,承認(rèn)是為了一會切割小矩形的時候祭务,方便計算高而特意用了正弦曲線,否則要是一點曲線規(guī)律都沒有怪嫌,那真的要用尺子去一個個量小矩形的高了,累死柳沙。

計算正弦曲線封閉區(qū)間和y軸相封存的面積

言歸正傳岩灭,說一下應(yīng)用題的要求吧。

如上圖的曲線是一個sin正弦函數(shù)赂鲤,公式 y=sin(x)噪径,我們要求的是這個函數(shù)與x軸閉區(qū)間[-0.5,1.0]所夾的部分面積,也就是綠色部分数初。

按照定積分的分割方法,我們把這片面積分割成n個小矩形,挨個計算面積匕荸,累加求和就是大約綠色部分的總面積了粟誓。分割的n越多,越接近于真實面積仑鸥,但是計算量也會增大吮播;反之分割的越少越省事,但是精度就下降了眼俊。大致如下圖這般:

用python畫了個示意圖意狠,以表明積分的原理


image.png
#include <stdio.h>
#include <math.h>

// 求曲線面積(定積分)。參數(shù)為疮胖,函數(shù)f(x)环戈,x軸上區(qū)間[begin,end]兩個點的值
// @param begin    x軸區(qū)間開始位置
// @param end      x軸區(qū)間結(jié)束位置
float integration(float begin, float end)
{
  float sum = 0;         //所有矩形的面積累加總和
  float n = 1000;        //將函數(shù)曲線下方劃為n個矩形,n值越大澎灸,精確值越高
  float width = (end - begin) / n;  //單個矩形寬度院塞,函數(shù)總長度除以矩形數(shù)量得到
  for(float i=1 ; i <= n ; i++)     //計算每個矩形的面積
  {
    float x = begin + width * i;     //通過i的遞增,得出每個矩形底部x點的值
    float y = fabs(sin(x));
    float area = y * width; //求x點對應(yīng)的y值击孩,取絕對值后迫悠,得到高度;再用底寬度乘高得出單個矩形面積
    sum += area;         //累加矩形面積
  }
  return sum;
}

int main(){
  printf("sin(x), x range is: [-0.5 , 1.0], area is: %f\n", integration(-0.5 , 1));
  return 0;
}

編譯執(zhí)行

$ g++ test.cpp
$ ./a.out
sin(x), x range is: [-0.5 , 1.0], area is: 0.582387

得出面積大概是0.582387巩梢。

到這里又開始有疑問了创泄,如何驗證正確率艺玲?

那么,我該祭出不定積分公式了鞠抑,面積

A = \int_a^b f(x)dx

則對公式進行推導(dǎo)出其原函數(shù)饭聚,然后限定[a,b]的區(qū)間,就是定積分了搁拙,求面積秒梳。

按上圖,積分函數(shù)f(x)=sin(x)箕速,公式為酪碘。
A = \int_{a}^ sin(x)dx
把原函數(shù)找出來
A = (-cos(x) + C) |_{a}^盐茎
上限b減去下限a兴垦,展開后常數(shù)C抵消了,最終成了
A = cos(a) - cos(b)

設(shè)置定積分下限a=-0.5字柠,上線b=1.0探越。但是結(jié)果卻錯了,算下來0.3多窑业,和我們上面的0.5多相差太大钦幔。原來看圖,就明白了常柄,圖是兩塊啊鲤氢,分布在y軸兩側(cè),不能直接這么算拐纱,應(yīng)該拆分一下铜异,變成[-0.5,0]和[0,1]兩個區(qū)間,分別運用上面的公式計算秸架,并取絕對值

A = |cos(-0.5) - cos(0)| + |cos(0) - cos(1)| = 0.582114

怎么樣揍庄,我們用代碼堆疊小方塊算出來的0.582387,是不是很接近用公式計算出來的結(jié)果0.582114东抹?只相差了0.000273蚂子。

另外一個驗證的方式,用高大上的在線定積分計算器 https://zh.numberempire.com/definiteintegralcalculator.php 核對下缭黔,輸入函數(shù)是sin(x)食茎,自變量x從-0.5到0,結(jié)果是 ?0.122417馏谨,取絕對值后是 0.122417别渔;然后自變量x再輸入0到1,結(jié)果是 0.459697,兩者相加得到 0.582114哎媚。

計算圓的面積

為了更好直觀的說明原理喇伯,我又換了一個容易計算的圖,如下

image.png

這次拨与,圓的函數(shù)方程式為 r^2 = (x-a)^2 + (y-b)^2 可以用這個來計算x和y的關(guān)系稻据,a、b是圓心坐標(biāo)买喧。

對于面積捻悯,我們有公式 s=πr^2 就可以推算出,再除以2就是半圓的面積淤毛。計算下來今缚,大概是6.2831852。

接下來低淡,我們繼續(xù)用上文的求定積分的方式荚斯,結(jié)合圓的函數(shù)方程式,計算出半圓面積查牌。

image.png
#include <stdio.h>
#include <math.h>

// 求曲線面積(定積分)。參數(shù)為滥壕,函數(shù)f(x)纸颜,x軸上區(qū)間[begin,end]兩個點的值
// @param begin    x軸區(qū)間開始位置
// @param end      x軸區(qū)間結(jié)束位置
float integration(float begin, float end)
{
  float r = 2;
  float a = 0;
  float b = 0;
  float sum = 0;         //所有矩形的面積累加總和
  float n = 1000;        //將函數(shù)曲線下方劃為n個矩形,n值越大绎橘,精確值越高
  float width = (end - begin) / n;  //單個矩形寬度胁孙,函數(shù)總長度除以矩形數(shù)量得到
  for(float i=1 ; i <= n ; i++)     //計算每個矩形的面積
  {
    float x = begin + width * i;     //通過i的遞增,得出每個矩形底部x點的值
    float y = sqrt(r*r - (x-a)*(x-a)) + b;
    float area = y * width; //求x點對應(yīng)的y值称鳞,取絕對值后涮较,得到高度;再用底寬度乘高得出單個矩形面積
    sum += area;         //累加矩形面積
  }
  return sum;
}

int main(){
  printf("circle, x range is: [-2.0 , 2.0], area is: %f\n", integration(-2.0 , 2.0));
  return 0;
}

編譯運行得到結(jié)果

circle, x range is: [-2.0 , 2.0], area is: 6.282976

這和我們用公式計算出來的結(jié)果6.2831852冈止,只相差了0.0002092狂票,萬分之2的差距,精度還可以熙暴。

接下來我們調(diào)高精度n闺属,設(shè)置成10000,計算后的結(jié)果是 6.283169周霉,相差了0.0000162掂器,這次是10萬分之一。

我們再調(diào)低精度n俱箱,到100国瓮,計算后的結(jié)果是 6.276536,這次相差0.0066492,差距拉大到千分之六了乃摹。

附錄

上文中的幾個圖像禁漓,我都是用python繪制出來,奉上python畫圖的源碼峡懈。

1. 正弦函數(shù)的圖

import matplotlib.pyplot as plt
import numpy as np
import mpl_toolkits.axisartist as axisartist

#創(chuàng)建畫布
fig = plt.figure(figsize=(8, 8))
#使用axisartist.Subplot方法創(chuàng)建一個繪圖區(qū)對象ax
ax = axisartist.Subplot(fig, 111)
#將繪圖區(qū)對象添加到畫布中
fig.add_axes(ax)


# 通過set_visible方法設(shè)置繪圖區(qū)所有坐標(biāo)軸隱藏
ax.axis[:].set_visible(False)

# 添加x坐標(biāo)軸璃饱,且加上箭頭
ax.new_floating_axis
ax.axis["x"] = ax.new_floating_axis(0,0)
ax.axis["x"].set_axisline_style("->", size = 1.0)

# 添加y坐標(biāo)軸,且加上箭頭
ax.axis["y"] = ax.new_floating_axis(1,0)
ax.axis["y"].set_axisline_style("-|>", size = 1.0)

# 設(shè)置x肪康、y軸上刻度顯示方向
ax.axis["x"].set_axis_direction("top")
ax.axis["y"].set_axis_direction("right")


#設(shè)置x荚恶、y坐標(biāo)軸的范圍
plt.xlim(-2,2)
plt.ylim(-1.5,1.5)


#plt.grid() # 網(wǎng)格線
plt.legend(loc="upper left") # 圖例說明,loc指定位置


#生成x步長為0.1的列表數(shù)據(jù)
x = np.linspace(-4, 4, 800)
y = np.sin(x)

#x - array( length N) 定義曲線的 x 坐標(biāo)
#y - array( length N ) 定義曲線的 y 坐標(biāo)
#如果數(shù)據(jù)點比較少的情況下磷支,會有縫隙出現(xiàn)谒撼,使用interpolate可以填充縫隙
plt.fill_between(x, y, where=(-0.5<=x) & (x<=1), facecolor='green', alpha=0.3, interpolate=True)

# 繪制填充紅色的矩形方塊,以展示積分的直觀圖
qujian = x[np.where((-0.5<=x) & (x<=1))]
i = 5
for xi in qujian:
  if i > 5 :
    rect = plt.Rectangle((xi,0),0.04,np.sin(xi)+0.02, color='red') # 之所以給加了個+0.02雾狈,是對畫出來的圖微微調(diào)整廓潜,更好看些。
    ax.add_patch(rect)
    i = 0
  i = i + 1

#繪制圖形
plt.plot(x,y, c='b')

plt.show()

注意上面的“繪制填充紅色的矩形方塊”部分的代碼善榛,如果不想繪制方塊辩蛋,只看原圖的話,把這部分代碼注釋掉就行移盆。

2. 圓形圖

這里上下文和上文繪制正弦函數(shù)是一樣的悼院,只把核心畫圓部分貼出來,覆蓋之前畫正弦函數(shù)的部分就行了

......
plt.legend(loc="upper left") # 圖例說明咒循,loc指定位置

# 圓的基本信息
# 1.圓半徑
r = 2.0
# 2.圓心坐標(biāo)
a, b = (0., 0.)
theta = np.arange(0, 2*np.pi, 0.01)
x = a + r * np.cos(theta)
y = b + r * np.sin(theta)
plt.plot(x, y) # 畫圓
plt.axis('equal')

#x - array( length N) 定義曲線的 x 坐標(biāo)
#y - array( length N ) 定義曲線的 y 坐標(biāo)
#如果數(shù)據(jù)點比較少的情況下据途,會有縫隙出現(xiàn),使用interpolate可以填充縫隙
plt.fill_between(x, y, where=(-r<=x) & (x<=r) & (y>=0), facecolor='green', alpha=0.3, interpolate=True)


# 繪制填充紅色的矩形方塊叙甸,以展示積分的直觀圖
qujian = np.linspace(-r, r, 400)
i = 5
for xi in qujian:
  if i > 5 :
    y = np.sqrt([(r*r - (xi-a)*(xi-a))]) + b # 根據(jù)圓的公式 r^2 = (x-a)^2 + (y-b)^2 推算出y
    rect = plt.Rectangle((xi-0.02,0), 0.04, y, color='red') # 畫矩形的時候有點偏差颖医,所以往左移了0.02。
    ax.add_patch(rect)
    i = 0
  i = i + 1

plt.show()

3. 除了正弦函數(shù)裆蒸,我還寫了余弦熔萧、指數(shù)等函數(shù)的面積計算

#include <stdio.h>
#include <math.h>

// 求曲線面積(定積分)。參數(shù)為光戈,函數(shù)f(x)哪痰,x軸上區(qū)間[begin,end]兩個點的值
// @param f(float) 這個參數(shù)是'函數(shù)指針'傳值,傳遞的是一個函數(shù)的地址久妆;這個函數(shù)用來求x軸上某一點對應(yīng)的y值晌杰。
// @param begin    x軸區(qū)間開始位置
// @param end      x軸區(qū)間結(jié)束位置
float integration(float f(float), float begin, float end)
{
  float sum = 0;         //所有矩形的面積累加總和
  float n = 1000;        //將函數(shù)曲線下方劃為n個矩形,n值越大筷弦,精確值越高
  float width = (end - begin) / n;  //單個矩形寬度肋演,函數(shù)總長度除以矩形數(shù)量得到
  for(float i=1 ; i <= n ; i++)     //計算每個矩形的面積
  {
    float x = begin + width * i;     //通過i的遞增抑诸,得出每個矩形底部x點的值
    float area = fabs(f(x)) * width; //求x點對應(yīng)的y值,取絕對值后爹殊,得到高度蜕乡;再用底寬度乘高得出單個矩形面積
    sum += area;         //累加矩形面積
  }
  return sum;
}

// 第一個例子,函數(shù)f(x)為正弦曲線
float function1(float x){
  return sin(x);
}

// 第二個例子梗夸,函數(shù)f(x)為余弦曲線
float function2(float x){
  return cos(x);
}

// 第三個例子层玲,函數(shù)f(x)為指數(shù)曲線
float function3(float x){
  return exp(x);
}

int main(){
  printf("sin(x), x range is: [-0.5 , 1.0], area is: %f\n", integration(function1, -0.5 , 1));
  printf("cos(x), x range is: [-1.0 , 1.0], area is: %f\n", integration(function2, -1 , 1));
  printf("exp(x), x range is: [ 0.0 , 2.0], area is: %f\n", integration(function3, 0 , 2));
  return 0;
}

編譯執(zhí)行

$ g++ test.cpp
$ ./a.out
sin(x), x range is: [-0.5 , 1.0], area is: 0.582387
cos(x), x range is: [-1.0 , 1.0], area is: 1.682942
exp(x), x range is: [ 0.0 , 2.0], area is: 6.395446

始于 2019-11-01,北京反症;更于 2019-11-02辛块,北京。

該文章在以下平臺同步

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末铅碍,一起剝皮案震驚了整個濱河市润绵,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌胞谈,老刑警劉巖尘盼,帶你破解...
    沈念sama閱讀 216,496評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異烦绳,居然都是意外死亡卿捎,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,407評論 3 392
  • 文/潘曉璐 我一進店門径密,熙熙樓的掌柜王于貴愁眉苦臉地迎上來娇澎,“玉大人,你說我怎么就攤上這事睹晒。” “怎么了括细?”我有些...
    開封第一講書人閱讀 162,632評論 0 353
  • 文/不壞的土叔 我叫張陵伪很,是天一觀的道長。 經(jīng)常有香客問我奋单,道長锉试,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,180評論 1 292
  • 正文 為了忘掉前任览濒,我火速辦了婚禮呆盖,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘贷笛。我一直安慰自己应又,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,198評論 6 388
  • 文/花漫 我一把揭開白布乏苦。 她就那樣靜靜地躺著株扛,像睡著了一般尤筐。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上洞就,一...
    開封第一講書人閱讀 51,165評論 1 299
  • 那天盆繁,我揣著相機與錄音,去河邊找鬼旬蟋。 笑死油昂,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的倾贰。 我是一名探鬼主播冕碟,決...
    沈念sama閱讀 40,052評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼躁染!你這毒婦竟也來了鸣哀?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,910評論 0 274
  • 序言:老撾萬榮一對情侶失蹤吞彤,失蹤者是張志新(化名)和其女友劉穎我衬,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體饰恕,經(jīng)...
    沈念sama閱讀 45,324評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡挠羔,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,542評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了埋嵌。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片破加。...
    茶點故事閱讀 39,711評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖雹嗦,靈堂內(nèi)的尸體忽然破棺而出范舀,到底是詐尸還是另有隱情,我是刑警寧澤了罪,帶...
    沈念sama閱讀 35,424評論 5 343
  • 正文 年R本政府宣布锭环,位于F島的核電站,受9級特大地震影響泊藕,放射性物質(zhì)發(fā)生泄漏辅辩。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,017評論 3 326
  • 文/蒙蒙 一娃圆、第九天 我趴在偏房一處隱蔽的房頂上張望玫锋。 院中可真熱鬧,春花似錦讼呢、人聲如沸撩鹿。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,668評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽三痰。三九已至吧寺,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間散劫,已是汗流浹背稚机。 一陣腳步聲響...
    開封第一講書人閱讀 32,823評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留获搏,地道東北人赖条。 一個月前我還...
    沈念sama閱讀 47,722評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像常熙,于是被迫代替她去往敵國和親纬乍。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,611評論 2 353

推薦閱讀更多精彩內(nèi)容