为什么我的python 3实现比我用C ++编写的实现快得多? [英] Why is my python 3 implementation much faster than the one I wrote in C++?
问题描述
我知道C ++应该比Python 3快得多,因为它是一种编译语言,而不是解释语言.
I know that C++ should be much faster than Python 3 because it is a compiled language as opposed to an interpreted language.
我写了2 两个使用Monte Carlo Simulation 来计算 Pi 的程序,一个在Python 3中,另一个在C ++中.
I wrote 2 two programs that use the Monte Carlo Simulation to calculate Pi, one in Python 3 and the other in C++.
事实证明,Python比C ++快大约16倍.如下面的照片所示,重复值为( 10,000,000 ),Python花费8.5秒,而C ++花费137.4秒.
Python turned out to be approximately 16x faster than C++. As seen in the photos bellow, with a repetition value of (10,000,000), Python takes 8.5 seconds whilst C++ takes 137.4 seconds.
我是C ++的新手,但我找不到在线解释此行为的帖子.
I'm new to C++ but I can't find posts online that explains this behavior.
根据这篇文章,C ++通常应该比Python快10倍-100倍,显然情况并非如此.我.
According to this post C++ in general should be 10x - 100x faster than Python, which is clearly not the case with me.
请帮助我理解为什么Python在我看来比C ++快得多.
Please help me understand why Python is significantly faster than C++ in my case.
我的结果:
C ++中的蒙特卡罗模拟(Pi的估算)
Python 3中的Monte Carlo模拟(Pi的估算)
Python源代码:
from random import random
import time
import sys
class MonteCarloSimulator(object):
def __init__(self, value):
self.value = value
if sys.platform == "win32":
self.G = ''
self.R = ''
self.END = ''
else:
self.G = '\033[92m'
self.R = '\033[1;31m'
self.END = '\033[0m'
def unit_circle(self, x, y):
if (x ** 2 + y ** 2) <= 1:
return True
else:
return False
def simulate(self):
print("\nProcessing calculations with a repetition value of " + self.R +
str(self.value) + self.END + " times.")
area_of_circle = 0
area_of_square = 0
start = time.clock()
for i in range(1, self.value):
x = random()
y = random()
if self.unit_circle(x, y):
area_of_circle += 1
area_of_square += 1
pi = (area_of_circle * 4) / area_of_square
runtime = time.clock() - start
print("\tCalculated Pi = " + self.G + str(pi) + self.END +
" ({0} seconds, {1} minutes)".format(round(runtime, 10),
round(runtime / 60, 10)))
print("Estimated Num of Pi is off by", abs(pi - 3.14159265359))
def main():
values = [1000, 10000, 100000, 1000000, 10000000, 100000000,1000000000, 10000000000]
for value in values: MonteCarloSimulator(value).simulate()
if __name__ == "__main__":
try:
main()
except KeyboardInterrupt:
print("\nQuitting...")
sys.exit(1)
C ++源代码:
#include <iostream> // std library
#include <random> // random number generator
#include <ctime> // calculating runtime
#include <cmath> // absolute value function
#include "MonteCarloSimmulation.hpp" // function prototypes
using namespace std;
const double g_PI {3.141592653589793238463};
int main()
{
// repitition values
long values[5] = {1000, 10000, 100000, 1000000, 10000000};//, 100000000, 1000000000, 10000000000};
// runs the simulation with the different repetition values
for (auto value : values)
simulate(value);
cout << "\nPress return to exit";
cin.get();
return 0;
}
/**
* The actual simulation
*/
void simulate(unsigned long value)
{
// start time for calculating runtime
const clock_t startTime = clock();
// area's variables
unsigned long area_of_circle = 0;
unsigned long area_of_square = 0;
// print the repitiion value
cout << "\nProcessing calculations with a repetition value of " << value <<
" times." << endl;
for (unsigned long i = 0; i != value; i++)
{
// gets random values from 0 to 1 for (x) and (y)
float x = randomFloat();
float y = randomFloat();
// checks if (x, y) are in a unit circle, if so increment circle area
if (unit_circle(x, y))
area_of_circle++;
area_of_square++;
}
// pi = area of circle * 4 / area of square
double calculatedPi = static_cast<double>(area_of_circle * 4) / area_of_square;
float endTime = static_cast<float>(clock() - startTime) / CLOCKS_PER_SEC;
// prints the value of calculated pi
cout << "\tCalculated Value of Pi: " << calculatedPi <<
" (" << endTime << " seconds, " << endTime/60 << " minutes)" << endl;
// difference between the calc value and pi
cout << "Estimated Num of Pi is off by " << abs(calculatedPi - g_PI) << '\n';
}
/**
* returns a random number from 0 to 1
*/
float randomFloat()
{
random_device rd;
default_random_engine generator(rd()); // rd() provides a random seed
uniform_real_distribution<float> distribution(0,1);
float x = distribution(generator);
return x;
}
/**
* checks if the two input parameters are inside a unit circle
*/
bool unit_circle(float x, float y)
{
if ((x*x + y*y) <= 1)
return true;
else
return false;
}
推荐答案
主要问题是您正在为C ++代码中的每个随机数重新生成一个随机数生成器.此外,您不会在启用优化(-O3
)的情况下进行编译.
The main problem is that you're reseeding a random number generator for each random number in your C++ code. Additionally you're not compiling with optimizations enabled (-O3
).
我将随机数生成器的初始化移到了randomFloat
函数之外(同样,您可以在函数内部使用static
变量):
I moved the initialization of the random number generator outside the randomFloat
function (equally, you could use static
variables inside the function):
random_device rd;
default_random_engine generator(rd()); // rd() provides a random seed
uniform_real_distribution<float> distribution(0,1);
float randomFloat() {
float x = distribution(generator);
return x;
}
并使用-O3
进行编译,现在C ++比Python快得多
and compiled with -O3
and now C++ is considerably faster than Python
另一种可能是python和C ++代码使用了不同的随机数生成器. Python random
模块( Merenne Twister 随机数生成器,它是一种快速PRNG,专门针对诸如蒙特卡洛等数值问题进行了优化; C ++中的default_random_engine
算法是实现定义的.正如 Melak47 指出的那样,您可以强制使用
Another possibility could be that python and C++ code use a different random number generator. Python random
module (C code here) uses a MT19937 Mersenne Twister random number generator that is a fast PRNG optimized specifically for numerical problems such as Monte Carlo; the algorithm of default_random_engine
in C++ is implementation-defined. As pointed out by Melak47, you can force the use of MT19937 PRNG in C++ with:
mt19937 generator(rd());
或
mt19937_64 generator(rd());
P.S.,Python超越C ++的表现并非闻所未闻; C ++算法重视通用性,而Python算法通常针对某些用例进行了优化.例如,请参见子字符串匹配.
这篇关于为什么我的python 3实现比我用C ++编写的实现快得多?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!