昨天写了一篇短文:
说说的那道求面积的小学六年级几何题:https://blog.csdn.net/dog250/article/details/84778239
这篇文章主要是就着一道简单的求面积的题目阐述了几种 求任意不规则图形面积的方法。
但由于时间关系,很多想说的没有在那篇文章中表达出来,随后收到了一些朋友圈以及公司钉钉群里讨论的反馈,和以往一样,关于这个话题,今晚再补上一篇,争取把该说的都说完。
非常感谢我们一位同事,在我昨晚大半夜发了那篇文章之后,还亲自画图算了一番,并和我讨论这个话题的形而上意义。下面是他的计算过程截图:
太厉害了,太认真了,太较真儿了,太重视过程了,太结果导向了,我们工作中太需要这种精神了!
我最大的问题在于不会这么仔细地去 把结果计算出来,我一般扫一眼有个思路就结束了,我高考的时候悲哀地直接写答案,而且还没有写对,结果就凉凉了…
所以我非常佩服他,我以后要向他学习!要有结果,而不是只有思路!
如本文题目所示,我把 求任意图形面积的方法 归纳为了三类:
- 土气的方法,即原始野人的方法
- 洋气的方法,即现代微积分的方法
- 中小学生方法,组合几何方法
关于 中小学生方法 上一篇文章已经有所涉及,无非就是套用一些已知的简单的规则图形的面积公式,然后加减即可,更深一步地,如果大家有孩子,我想孩子们会教会我们更多。
本文侧重于 土气的方法 和 洋气的方法 。
首先,我们忘掉所有知识,来猜测一下野人是如何做的。我重复一遍我的猜测:
野人们在采用这种方法的时候,其实已经明白 同样材质的东西,A比B大x倍,A就比B重x倍 这个道理了。在此之前,野人们可能会用纯比较大小的方法,也就是用相同大小的小石子铺在单位正方形和不规则图形上,分别恰好铺满,然后数小石子的数量,显而易见,小石子越小,计算结果越精确。
是不是很土气呢?
是很土气,如果我们现在还有人这么算,估计会被嘲笑吧,别人套公式妙算的问题,他在那里摆石子,铺泥巴折腾大半天,最后结果还没有套公式的结果精确,会很汗颜吧…
但这不是我要说的,我要说的是 计算机其实很擅长干这个“很土气”的事情。
我们来看一个问题,用这种方法让计算机去算一下。就简单直接点,求圆的面积吧。当然,你肯定不能用 π \pi π和微积分。
先给出一个朴素的算法,计算机会依次从左到右,从上到下扫描下图所有的像素,然后简单的进行 数数 就行:
如果我们相信 随机事件前后无关联 的统计特性,那么我们可以用更加 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,圆和正方形之间的面积之比就是:
s = π × 0. 5 2 1 = 3.1415926 × 0.25 = 0.78539815 s=\dfrac{\pi \times 0.5^2}{1}=3.1415926\times 0.25=0.78539815 s=1π×0.52=3.1415926×0.25=0.78539815
然后运行我们的程序,随着计算次数的增加,精度将变好:
[root@localhost rand]# ./a.out 10
5 0.500000
[root@localhost rand]# ./a.out 100
78 0.780000
[root@localhost rand]# ./a.out 1000
765 0.765000
[root@localhost rand]# ./a.out 10000
7784 0.778400
[root@localhost rand]# ./a.out 100000
78554 0.785540
[root@localhost rand]# ./a.out 1000000
784448 0.784448
[root@localhost rand]# ./a.out 10000000
7853091 0.785309
[root@localhost rand]#
结果已经很不错了!好玩吗?
方法是比较土气,但是原始的野计算机算起来也蛮快的。
上面的代码,本来应该用double精度的数去打点的,然而代码会稍微复杂写,掩盖了想表达的思想,所以就用int型了,然后用扩大范围的方式来提高分辨率,我觉得1000足够了,当然,范围越大,分辨率越高。
说完了比较土的方法后,下面来看看比较洋气的方法,即使用现代微积分的做法。
我们依然用求圆的面积作为话题切入。
如果把圆放进笛卡尔坐标系中,计算它的面积,不就是求一段曲线关于x的积分吗?
只要求出 x 2 + y 2 = 1 x^2+y^2=1 x2+y2=1在定义域 [ 0 , 1 ] [0,1] [0,1]上的曲线 y = 1 − x 2 y=\sqrt{1-x^2} y=1−x2积分,用牛顿-莱布尼兹公式求解即可。
我们来试一下。
S = 4 × ∫ 0 1 1 − x 2 d x S=4\times\displaystyle\int_0^1\sqrt{1-x^2}dx S=4×∫011−x2dx
第二类换元法三角代换,设:
x = sin t x=\sin t x=sint
则有:
d x = cos t d t dx=\cos t dt dx=costdt
带入即可得:
S = 4 × ∫ 1 − sin 2 t cos t d t = 4 × ∫ 0 π 2 cos 2 t d t S=4\times \displaystyle\int_{}^{}\sqrt{1-\sin^2 t}\cos t dt=4\times \displaystyle\int_{0}^{\frac{\pi}{2}}\cos^2 t dt S=4×∫1−sin2tcostdt=4×∫02πcos2tdt
上面太长了,我们另起一行接着写:
S
=
4
×
1
2
×
∫
0
π
2
(
1
+
cos
2
t
)
d
t
S=4\times \dfrac{1}{2}\times\displaystyle\int_{0}^{\frac{\pi}{2}}(1+\cos 2t) dt
S=4×21×∫02π(1+cos2t)dt
S
=
2
×
(
[
t
]
0
π
2
+
[
1
2
sin
2
t
]
0
π
2
)
=
π
S=2\times ([t]_0^{\frac{\pi}{2}}+[\dfrac{1}{2}\sin 2t]_0^{\frac{\pi}{2}})=\pi
S=2×([t]02π+[21sin2t]02π)=π
结果就是 π \pi π,如果上面的推导过程你用半径 r r r代替 1 1 1,结果就是 π r 2 \pi r^2 πr2。
怎么样,洋气吧。也挺好玩的。
现在的问题是,后面的这种洋气的做法,积分和 π \pi π的关系,这说起来就要另起一文了,说实话光 π \pi π的话题就够复杂的了,话说古代 π \pi π不准,车轮子转着都颠簸。
不管怎么说,不管是土气的方法还是洋气的方法,我们都没有主动的引入 π \pi π去参与圆面积的计算,这便是最有意思的地方了。
现在回到现实。
我觉得这个 “求圆的面积” 问题真要问起来的话,其实也简单,不用考虑这么复杂,拿起计算器瞬间就有了答案,即便是面对 不规则图案的面积求解 ,用Python,matlab也能秒解,何必去折腾什么微积分,关键是你微积分也只能在纸上比划比划,设计到那些非四则混合运算时,你不还得查表?再者说了,就算你折腾出一堆公式,想让计算机帮你算,你不还得编程?
所以说,这种问题啊,直接用Python吧,超级多的数学库可以用。
然而,我不会Python,我也不会编程,唉…
浙江温州皮鞋?湿,下雨☔️进水不会胖!