python - 为什么我的 python 3 实现比我用 C++ 编写的快得多?

标签 python c++ performance simulation montecarlo

我知道 C++ 应该比 Python 3 快得多,因为它是一种编译型语言,而不是解释型语言。

我写了 2 两个使用 Monte Carlo Simulation 计算 Pi 的程序,一个在 Python 3 中,另一个在 C++ 中。

事实证明,Python 比 C++ 快大约 16 倍。如下图所示,重复值为 (10,000,000),Python 需要 8.5 秒,而 C++ 需要 137.4 秒。

我是 C++ 的新手,但我在网上找不到解释此行为的帖子。

根据 this post C++ 通常应该比 Python 快 10 到 100 倍,但我显然不是这种情况。

请帮助我理解为什么在我的案例中 Python 比 C++ 快得多。

我的结果:

C++ 中的蒙特卡罗模拟(Pi 的估计) Monte Carlo Simulation (Estimation of Pi) using C++

Python 3 中的蒙特卡罗模拟(Pi 的估计) Monte Carlo Simulation (Estimation of Pi) using python 3

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)。

我将随机数生成器的初始化移到了 randomFloat 函数之外(同样,您可以在函数内部使用 static 变量):

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 快得多


另一种可能性是 python 和 C++ 代码使用了不同的随机数生成器。 python random module ( C code here ) 使用 MT19937 Mersenne Twister随机数生成器,它是一种快速 PRNG,专门针对蒙特卡罗等数值问题进行了优化; C++ 中 default_random_engine 的算法是实现定义的。正如 Melak47 指出的那样, 你可以强制使用 MT19937 C++ 中的 PRNG:

mt19937 generator(rd());

mt19937_64 generator(rd());

P.S.,Python 优于 C++ 并非闻所未闻; C++ 算法重视通用性,而 Python 算法通常针对某些用例进行了相当优化。例如,请参阅 substring matching 上的这个问题.

关于python - 为什么我的 python 3 实现比我用 C++ 编写的快得多?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37254061/

相关文章:

c++ - 在 Windows 上显示向上/向下箭头 C++

asp.net - 哪个性能最好 : Classic ASP, ASP.NET WebForms 或 ASP.NET MVC?

python - 在两个维度上将零填充到张量

python - 无法使用 Celery + Django 在 tasks.py 中导入模型

python - 在 python igraph 中通过源-目标-元组选择单个边

performance - Scala 的 .min 如何避免装箱和拆箱的惩罚?

java - Java Hotspot 服务器中多态性的高成本

python - telnet 上 ssh 等效的 read_until 和 read_very_eager 方法是什么?

c++ - 将较小的整数类型分配给较大的整数类型会不安全吗?

c++ - 什么时候不能将对象转换为引用?