土氣和洋氣的方法不用π求圓的面積
昨天寫了一篇短文:
說說的那道求面積的小學六年級幾何題 : ofollow,noindex" target="_blank">https://blog.csdn.net/dog250/article/details/84778239
這篇文章主要是就著一道簡單的求面積的題目闡述了幾種 求任意不規則圖形面積的方法 。
但由於時間關係,很多想說的沒有在那篇文章中表達出來,隨後收到了一些朋友圈以及公司釘釘群裡討論的反饋,和以往一樣,關於這個話題,今晚再補上一篇,爭取把該說的都說完。
非常感謝我們一位同事,在我昨晚大半夜發了那篇文章之後,還親自畫圖算了一番,並和我討論這個話題的形而上意義。下面是他的計算過程截圖:

太厲害了,太認真了,太較真兒了,太重視過程了,太結果導向了,我們工作中太需要這種精神了!
我最大的問題在於不會這麼仔細地去 把結果計算出來 ,我一般掃一眼有個思路就結束了,所以我非常佩服他,我以後要向他學習!要有結果,而不是隻有思路!
如本文題目所示,我把 求任意圖形面積的方法 歸納為了三類:
- 土氣的方法,即原始野人的方法
- 洋氣的方法,即現代微積分的方法
- 中小學生方法,組合幾何方法
關於 中小學生方法 上一篇文章已經有所涉及,無非就是套用一些已知的簡單的規則圖形的面積公式,然後加減即可,更深一步地,如果大家有孩子,我想孩子們會教會我們更多。
本文側重於 土氣的方法 和 洋氣的方法 。
首先,我們忘掉所有知識,來猜測一下野人是如何做的。我重複一遍我的猜測:

野人們在採用這種方法的時候,其實已經明白 同樣材質的東西,A比B大x倍,A就比B重x倍 這個道理了。在此之前,野人們可能會用純比較大小的方法,也就是用相同大小的小石子鋪在單位正方形和不規則圖形上,分別恰好鋪滿,然後數小石子的數量,顯而易見,小石子越小,計算結果越精確。
是不是很土氣呢?
是很土氣,如果我們現在還有人這麼算,估計會被嘲笑吧,別人套公式妙算的問題,他在那裡擺石子,鋪泥巴折騰大半天,最後結果還沒有套公式的結果精確,會很汗顏吧…
但這不是我要說的,我要說的是 計算機其實很擅長幹這個“很土氣”的事情 。
我們來看一個問題,用這種方法讓計算機去算一下。就簡單直接點,求圓的面積吧。當然,你肯定不能用 和微積分。
先給出一個樸素的演算法,計算機會依次從左到右,從上到下掃描下圖所有的畫素,然後簡單的進行 數數 就行:

如果我們相信 隨機事件前後無關聯 的統計特性,那麼我們可以用更加 Trick 的方法來任意精度的計算圓的面積,我們不再需要一個個地進行數數或者稱重,我們會相信 “扔到圖形中一個石子,它掉進某個區域的概率和該區域的大小成正比”!
這就是基於 概率統計理論 的 蒙特卡羅方法 ,具體參見阮一峰的一篇部落格:
蒙特卡羅方法入門 : http://www.ruanyifeng.com/blog/2015/07/monte-carlo-method.html
我這裡有一個程式碼:
#include <stdio.h> #include <stdlib.h> #include <fcntl.h> int main(int argc, char **argv) { unsigned int x, y; int c = 0; // l控制精度 int l = atoi(argv[1]); int p = l; double k; FILE *fp = fopen("/dev/urandom", "r"); while (l --) { // 隨機產生點的x座標,限制在邊長1000的單位正方形內 fread(&x, sizeof(int), 1, fp); x = x%1000; // 隨機產生點的y座標,限制在邊長1000的單位正方形內 fread(&y, sizeof(int), 1, fp); y = y%1000; // 判斷是否在單位正方形的內切圓中,如果在,則計數器遞增! if ((x-500)*(x-500) + (y-500)*(y-500) < 250000|| (x-500)*(x-500) + (y-500)*(y-500) == 250000) c ++; } fclose(fp); k = (double)c/(double)p; printf("%d%f\n", c, k); }
我們先有計算器算一下一個圓的面積和其外切正方形面積之間的比值,簡單起見,設單位正方形邊長為1,則其面積就是1,那麼其內切圓的半徑就是0.5,圓和正方形之間的面積之比就是:
然後執行我們的程式,隨著計算次數的增加,精度將變好:
[root@localhost rand]# ./a.out 10 50.500000 [root@localhost rand]# ./a.out 100 780.780000 [root@localhost rand]# ./a.out 1000 7650.765000 [root@localhost rand]# ./a.out 10000 77840.778400 [root@localhost rand]# ./a.out 100000 785540.785540 [root@localhost rand]# ./a.out 1000000 7844480.784448 [root@localhost rand]# ./a.out 10000000 78530910.785309 [root@localhost rand]#
結果已經很不錯了!好玩嗎?
方法是比較土氣,但是原始的野計算機算起來也蠻快的。
說完了比較土的方法後,下面來看看比較洋氣的方法,即使用現代微積分的做法。
我們依然用求圓的面積作為話題切入。
如果把圓放進笛卡爾座標系中,計算它的面積,不就是求一段曲線關於x的積分嗎?
只要求出 在定義域 上的曲線 積分,用牛頓-萊布尼茲公式求解即可。
我們來試一下。
第二類換元法三角代換,設:
則有:
帶入即可得:
上面太長了,我們另起一行接著寫:
結果就是 ,如果上面的推導過程你用半徑 代替 ,結果就是 。
怎麼樣,洋氣吧。也挺好玩的。
現在的問題是,後面的這種洋氣的做法,積分和 的關係,這說起來就要另起一文了,說實話光 的話題就夠複雜的了,話說古代 不準,車輪子轉著都顛簸。
不管怎麼說,不管是土氣的方法還是洋氣的方法,我們都沒有主動的引入 去參與圓面積的計算,這便是最有意思的地方了。
現在回到現實。
我覺得這個 “求圓的面積” 問題真要問起來的話,其實也簡單,不用考慮這麼複雜,拿起計算器瞬間就有了答案,即便是面對 不規則圖案的面積求解 ,用Python,matlab也能秒解,何必去折騰什麼微積分,關鍵是你微積分也只能在紙上比劃比劃,設計到那些非四則混合運算時,你不還得查表?再者說了,就算你折騰出一堆公式,想讓計算機幫你算,你不還得程式設計?
所以說,這種問題啊,直接用Python吧,超級多的數學庫可以用。
然而,我不會Python,我也不會程式設計,唉…
浙江溫州皮鞋:mans_shoe:溼,下雨:umbrella:️進水不會胖!