C++ 加速montecarlo-Pi
我已经编写了一个C++程序,通过“将随机点抛入四分之一个圆中,然后计数等”来计算pi。现在我的程序在我看来有点慢,我已经考虑了一些改进来加速它(下面是源代码)。C++ 加速montecarlo-Pi,c++,multithreading,C++,Multithreading,我已经编写了一个C++程序,通过“将随机点抛入四分之一个圆中,然后计数等”来计算pi。现在我的程序在我看来有点慢,我已经考虑了一些改进来加速它(下面是源代码)。 我的第一个想法是使用OpenMP使其成为多线程,即将(i)和(II)之间的代码拆分为多个线程,这样我就可以在不必等待更长时间的情况下(在八核系统上)拥有近十倍的轮数。 我的另一个想法是使用全局变量和指针,所以我只需要复制指针,而不是整数的元组。退税是(idk)? 那么,我还能做些什么来加速程序呢?我主要使用windows,但我也可以使用
我的第一个想法是使用OpenMP使其成为多线程,即将(i)和(II)之间的代码拆分为多个线程,这样我就可以在不必等待更长时间的情况下(在八核系统上)拥有近十倍的轮数。
我的另一个想法是使用全局变量和指针,所以我只需要复制指针,而不是整数的元组。退税是(idk)?
那么,我还能做些什么来加速程序呢?我主要使用windows,但我也可以使用Unix/Linux。
多谢各位 代码部分:
#include <cstdlib>
#include <iostream>
#include <tuple>
#include <math.h>
#include <time.h>
#include <omp.h>
#include <sys/time.h>
#define RAND_MAX 32000
#define LOOPS 1000000
inline std::tuple<int, int> Throw_points(void)
{
int i = 0, j = 0;
i = rand() % 1000;
j = rand() % 1000;
return std::make_tuple(i, j);
}
inline bool is_in_circle(std::tuple<int, int> point)
{
if ((pow(std::get<0>(point), 2) + pow(std::get<1>(point), 2)) <= pow(1000, 2))
return true;
else
return false;
}
inline double pi(void)
{
srand(time(NULL));
long long int in_circle = 0;
long long int out_circle = 0;
for (int i = 0; i < LOOPS; i++)
{
if (is_in_circle(Throw_points()))
in_circle++;
out_circle++;
}
return double(in_circle) / double(out_circle) * 4;
}
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#定义RAND_MAX 32000
#定义循环1000000
内联标准::元组抛出点(空)
{
int i=0,j=0;
i=rand()%1000;
j=rand()%1000;
返回std::make_tuple(i,j);
}
内联布尔是圆中的(标准::元组点)
{
如果((pow(std::get(point),2)+pow(std::get(point),2))一些随机观察:
- 通过乘法求平方可能比调用
pow
更快。特别是,您不希望每次都计算常量pow(1000,2)
int
计数器可能比long-long
快-您已经限制了可由int
表示的循环数
- 通过引用传递可能会更快。或者可能会更慢,因为类型很小。或者可能不会有什么区别,因为函数应该是内联的
if(X)返回true;else返回false;
而不是返回X;
很奇怪,但可能不会影响性能
rand()
对于蒙特卡罗模拟来说,随机性可能不够;它的目的是速度快,但质量不高。不幸的是,好的伪随机生成器非常慢。C++11库有几个选项
如果你真的让它多线程,那么确保每个线程都有一个不同的随机种子;否则,它们只会复制彼此的工作。你将无法使用rand()
,因为它不是线程安全的。我只是对这一点做了一些研究。实际上,原始帖子评论中的所有建议(包括我自己的建议)几乎没有任何区别
然而,去掉元组
inline void Throw_points(int&i, int&j)
{
i = rand() % 1000;
j = rand() % 1000;
}
inline bool is_in_circle(int i, int j)
{
return i*i + j*j < 1000000;
}
inlinevoid抛出点(int&i,int&j)
{
i=rand()%1000;
j=rand()%1000;
}
内联布尔是圆中的(inti,intj)
{
返回i*i+j*j<1000000;
}
把程序加快了五倍
顺便说一句,我在这里使用了boost::progress\u timer解决方案:性能观察。使用分析工具;这会告诉您代码在哪里花费时间。通常这总是令人惊讶
如果你在gcc土地使用gprof中,这是一种计算π
的慢方法;IIRC我的数学课程,精度是1/sqrt(循环)
(但我可能是错的)。所以读一些数学书来计算π
更快!阅读wikipage上的内容不会有多大帮助,但你应该缓存pow(1000,2)的结果
,或者最后将其替换为1000*1000
,这比pow
快得多,编译器将为您缓存结果。@basilestrynkevitch:我必须使用此方法,否则我已经切换了…然后使用#pragma
-sAlso,将a&添加到is#u in_circle的函数参数中。您继续复制y我们的元组现在可以通过引用传递了。@ViníciusGobboA.deOliveira关于省略pow(…)的评论也适用于其他平方运算:我预计std::get(point)*std::get(point)
比pow(std::get(point),2)快得多
。使用兰德是一个先决条件,pi非常好(3.145等)。是的,但我认为迈克的观点是兰德()这不是一个高质量的PRNG。@PeteBecker:我知道,但我们只需要计算圆周率,直到komma之后的第二个数字…@arc_Luse:如果它对这个任务来说足够好,那就好了。但是值得记住的是,当你需要统计上良好的随机性时,它不是很好。rand()
。对于这个特定的任务来说,它是足够随机的,但对于实际问题,我根本不相信它。除了使用rand
,一个可能更严重的问题是使用%运算符来限制范围:某些值会比其他值(稍微)更频繁地出现。