圆周率Pi的求解
字节跳动面试时,算法部分给我丢了这个开胃小菜;当时使用的是蒙特卡洛模拟,效果还不错。
1. 蒙特卡洛模拟
蒙特卡洛模拟用于模拟一个随机过程中不同结果可能出现的概率。那怎么使用蒙特卡洛模拟来求解圆周率Pi呢?
1.1 思想
蒙特卡洛模拟的思想是很简单的,比如:在以[0,0],[1,1]为顶点的正方形内进行随机投点,如果该随机点到圆心[0,0]的距离小于1,则说明该点位于以[0,0]为圆心,1为半径的1/4圆内;当试验次数达到无穷时,位于圆内点的数目和总投点数目之比无限接近圆和正方形面积之比,即pi/4。
1.2 求解代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| #include <iostream> #include <cstdlib> #include <ctime> #include <vector>
using namespace std;
class Solution{ public: float calcPi(const int numOfPoints){ auto getDist = [](const vector<float>& point){ return point[0] * point[0] + point[1] * point[1]; }; int legal_num = 0; for(int i = 1; i<= numOfPoints; ++i){ vector<float> point = getNextRandom(); if(getDist(point) <= 1.0f){ ++legal_num; } } return 4.0*(float)legal_num/(float)numOfPoints; } vector<float> getNextRandom(){ int x = rand() % 100 + 1; int y = rand() % 100 + 1; return {x/100.0f, y/100.0f}; } };
int main(){ srand(time(0)); Solution s; const int numOfPoints = 10* 10000; std::cout << s.calcPi(numOfPoints) << std::endl; return 0; }
|
从这里的输出结果可以看到,使用蒙特卡洛求解的结果精度明显不够,不过思想简单算法实现容易。
我当时面试时,输出的结果差不多就是这个样子;面试官看后说,有没有办法使得结果更加精确一些呢?
我说:可以增大样本点的个数;或者实验多组数据求取平均值;但是感觉这个模拟方法不太好。
面试官又问:还有优化的方法么?这个随机数的生成可以优化一下么?
我想:随机数的生成?什么意思?难道是在说随机数的底层生成算法上解决?虽然有接触过线性同余法,但是这水平更不不够呀。难道是说,想要保证随机数不重复?使用哈希?没想明白,就说不会了。
有想法的朋友可以告知我一下哈~
2. 级数求解
在高中或者在大学数学中,我们可能会看到这样一个公式:(通过arctanx级数求和得到)
Pi/4 = 1 - 1/3 + 1/5 - 1/7 + 1/9 - 1/11 + 1/13 ...
其实这是一个交错级数(以0为极限,必收敛),是数学家莱布尼茨发现的计算圆周率Pi的公式,它的通项表达为如下:
2.1 代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| #include <iostream> using namespace std;
class Solution{ public: double calcPi(const unsigned int n){ double sum = 0.0, symbol = 1.0; for(int i = 0; i<=n; ++i){ sum += symbol/(2 * i + 1); symbol = -symbol; } return 4 * sum; } };
int main(){ Solution s; const unsigned int n = 10 * 10000; std::cout << s.calcPi(n) << std::endl; return 0; }
|
从输出结果可以看出,使用莱布尼茨级数来计算Pi值精度更好,值得一提的是该算法的求解效率大大优于蒙特卡洛模拟。
好了,关于圆周率Pi的求解方法暂时介绍到这里,大家有什么更好的方法,可以在下面畅所欲言~
Last updated: