本帖最后由 robe.zhang 于 2021-7-29 11:49 编辑
【ALINX AXU2CGB试用】蒙特卡罗算法计算圆周率 PI
蒙特卡洛算法理论就是用统计学来计算圆周率PI。
乍一听是不是觉得很神奇,统计学和圆周率算法能扯上关系,先不说蒙特卡洛算法,也不管能不能扯上关系,先讲个故事:
(图片是借用网上的图片,如有侵权必究,请告知哈) 如果我在地上画一个正方形,再以正方形一个顶点为圆心边长为半径,画个1/4 圆弧,如上图。
现在天上下雨了,因为雨点密度是均匀的,所以落入正方形内的雨点的数量和落入圆弧内的雨点的数量之比,就等于正方形面积和1/4圆的面积之比。正方形面积等于RxR,圆弧面积等于PIxRxR/4,PI 诞生了,并且比值中的R可以约掉的,pi 的计算公式如下:
PI : 4 = 圆弧面积:正方形面积 = 圆弧内雨点数量:正方形内雨点数量。
OK,现在统计正方形内雨点数量,和圆弧内雨点数量,就可以算出PI 了。
这个故事就是蒙特卡罗算法计算圆周率的理论,就是这么合情合理又神奇的统计理论计算圆周率 PI。计算出的Pi数值准不准确,就依赖数据量了,毕竟是统计理论得出的数据。
理论有了,开始操作,统计雨点不现实,那就用随机数产生笛卡尔系坐标点,计算点到圆心的距离,大于边长R,落入上图蓝色区域,小于边长R落入红色区域,统计红色区域点的个数和蓝色区域点的个数,搞定。
以下是程序跑出的结果:
笔者把 PI数值随雨点数量的变化趋势,画了个图,从图上能看出来统计了1万多组数据, 计算出的PI数值 一开始剧烈波动,2000 组数据时基本稳定在 3 左右,然后就是一路飘忽不定,收敛很慢,也不准确,满满的统计学特征。 用物理上专业术语描述,这是个欠阻尼系统,振荡会一直持续下去,振幅会随着时间(雨点数量)增加变小,但永远不会为零
有个日本人用这个算法计算PI,在自己电脑上跑了1年,计算结果据说比较准确。
此算法也可以在黑金开发板上跑1年,看看数据怎么样
上源码:源码很短,用 linux bash 语言写的,能在开发板上直接跑 - #!/bin/bash
- value_x=
- value_y=
- value_dist=
- value_edge=$(( 32767 * 32767 ))
- count_cycle=0
- count_edge=0
- count_total=0
- vaule_pi_min=
- vaule_pi_max=
- for((;;)); do
- value_x=$RANDOM
- value_y=$RANDOM
- value_dist=$(( $value_x * $value_x + $value_y * $value_y ))
- if (( "${value_dist}" < "${value_edge}" )) ;then (( count_cycle++ )); fi
- if (( "${value_dist}" == "${value_edge}" )) ;then (( count_edge++ )); fi
- (( count_total++ ))
- vaule_pi_min=$(echo "scale=50;4 * $count_cycle / $count_total" |bc )
- vaule_pi_max=$(echo "scale=50;4 * ($count_cycle + $count_edge) / $count_total " |bc )
- echo "point($value_x,$value_y),dist($value_dist). count: cycles($count_cycle),edge($count_edge),total($count_total). PI[$vaule_pi_min,$vaule_pi_max]" | tee -a pi.data
- done;
复制代码
这个代码运行时,会在同目录中产生 pi.data 记录文件,如果第一次跑后,第二次想接着上一次的数据跑,只需要把 pi.data 中最后一次记录中的 cycles,edge,total 数值,赋值给程序中的 count_cycle,count_edge,count_total 三个变量即可。
可以利用零散时间,累计跑一年,看看结果怎么样
|