c++ - Python 和 C++ 之间不寻常的速度差异

标签 c++ python algorithm performance

我最近写了一个简短的算法来计算 happy numbers在 python 。该程序允许您选择一个上限,它将确定其下方的所有快乐数字。为了进行速度比较,我决定将我所知道的算法从 python 到 c++ 进行最直接的翻译。

令人惊讶的是,c++ 版本的运行速度明显慢于 python 版本。发现前 10,000 个快乐数字的执行时间之间的准确速度测试表明,python 程序平均运行时间为 0.59 秒,c++ 版本平均运行时间为 8.5 秒。

我将这种速度差异归因于这样一个事实,即我必须在已经内置的 c++ 版本中为部分计算(例如确定元素是否在列表/数组/vector 中)编写辅助函数 python 语言。

首先,这是否是造成如此荒谬的速度差异的真正原因,其次,我怎样才能将 c++ 版本更改为比 python 版本更快的执行(我认为应该是这样)。

两段代码,速度测试在这里:Python Version , C++ Version .感谢您的帮助。

#include <iostream>
#include <vector>
#include <string>
#include <ctime>
#include <windows.h>

using namespace std;

bool inVector(int inQuestion, vector<int> known);
int sum(vector<int> given);
int pow(int given, int power);
void calcMain(int upperBound);

int main()
{
    while(true)
    {
        int upperBound;
        cout << "Pick an upper bound: ";
        cin >> upperBound;
        long start, end;
        start = GetTickCount();
        calcMain(upperBound);
        end = GetTickCount();
        double seconds = (double)(end-start) / 1000.0;
        cout << seconds << " seconds." << endl << endl;
    }
    return 0;
}

void calcMain(int upperBound)
{
    vector<int> known;
    for(int i = 0; i <= upperBound; i++)
    {
        bool next = false;
        int current = i;
        vector<int> history;
        while(!next)
        {
            char* buffer = new char[10];
            itoa(current, buffer, 10);
            string digits = buffer;
            delete buffer;
            vector<int> squares;
            for(int j = 0; j < digits.size(); j++)
            {
                char charDigit = digits[j];
                int digit = atoi(&charDigit);
                int square = pow(digit, 2);
                squares.push_back(square);
            }
            int squaresum = sum(squares);
            current = squaresum;
            if(inVector(current, history))
            {
                next = true;
                if(current == 1)
                {
                    known.push_back(i);
                    //cout << i << "\t";
                }
            }
            history.push_back(current);
        }
    }
    //cout << "\n\n";
}

bool inVector(int inQuestion, vector<int> known)
{
    for(vector<int>::iterator it = known.begin(); it != known.end(); it++)
        if(*it == inQuestion)
            return true;
    return false;
}

int sum(vector<int> given)
{
    int sum = 0;
    for(vector<int>::iterator it = given.begin(); it != given.end(); it++)
        sum += *it;
    return sum;
}

int pow(int given, int power)
{
    int original = given;
    int current = given;
    for(int i = 0; i < power-1; i++)
        current *= original;
    return current;
}

#!/usr/bin/env python

import timeit

upperBound = 0

def calcMain():
    known = []
    for i in range(0,upperBound+1):
        next = False
        current = i
        history = []
        while not next:
            digits = str(current)
            squares = [pow(int(digit), 2) for digit in digits]
            squaresum = sum(squares)
            current = squaresum
            if current in history:
                next = True
                if current == 1:
                    known.append(i)
                    ##print i, "\t",
            history.append(current)
    ##print "\nend"

while True:    
    upperBound = input("Pick an upper bound: ")
    result = timeit.Timer(calcMain).timeit(1)
    print result, "seconds.\n"

最佳答案

对于 100000 个元素,Python 代码需要 6.9 秒,而 C++ 最初需要 37 秒以上。

我对您的代码进行了一些基本优化,并设法使 C++ 代码比 Python 实现快 100 倍以上。它现在在 0.06 秒内处理 100000 个元素。这比原始 C++ 代码快 617 倍。

最重要的是在 Release模式下编译,并进行所有优化。这段代码在 Debug模式下确实慢了几个数量级。

接下来,我将解释我所做的优化。

  • 将所有 vector 声明移出循环;将它们替换为 clear() 操作,这比调用构造函数要快得多。
  • 将 pow(value, 2) 的调用替换为乘法:value * value。
  • 我没有使用平方 vector 并在其上调用 sum,而是仅使用整数对值求和。
  • 避免了所有字符串操作,与整数操作相比,这些操作非常慢。例如,可以通过重复除以 10 并获取结果值的模 10 来计算每个数字的平方,而不是将值转换为字符串,然后将每个字符转换回 int。
  • 避免了所有 vector 拷贝,首先将值传递替换为引用传递,最后完全消除辅助函数。
  • 删除了一些临时变量。
  • 可能还有很多我忘记的小细节。并排比较你的代码和我的代码,看看我做了什么。

使用预先分配的数组而不是 vector 可以进一步优化代码,但这需要更多的工作,我将把它作为练习留给读者。 :P

这是优化后的代码:

#include <iostream>
#include <vector>
#include <string>
#include <ctime>
#include <algorithm>
#include <windows.h>

using namespace std;

void calcMain(int upperBound, vector<int>& known);

int main()
{
    while(true)
    {
        vector<int> results;
        int upperBound;
        cout << "Pick an upper bound: ";
        cin >> upperBound;
        long start, end;
        start = GetTickCount();
        calcMain(upperBound, results);
        end = GetTickCount();
        for (size_t i = 0; i < results.size(); ++i) {
            cout << results[i] << ", ";
        }
        cout << endl;
        double seconds = (double)(end-start) / 1000.0;
        cout << seconds << " seconds." << endl << endl;
    }
    return 0;
}

void calcMain(int upperBound, vector<int>& known)
{
    vector<int> history;
    for(int i = 0; i <= upperBound; i++)
    {
        int current = i;
        history.clear();
        while(true)
        {
                int temp = current;
                int sum = 0;
                while (temp > 0) {
                    sum += (temp % 10) * (temp % 10);
                    temp /= 10;
                }
                current = sum;
                if(find(history.begin(), history.end(), current) != history.end())
                {
                        if(current == 1)
                        {
                                known.push_back(i);
                        }
                        break;
                }
                history.push_back(current);
        }
    }
}

关于c++ - Python 和 C++ 之间不寻常的速度差异,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1269795/

相关文章:

android - 智能指针(Android强指针)引用类型拷贝

c++ - 检查一个程序中是否所有 C++ 函数都抛出异常的工具

c++ - pthread_create 参数传递错误

python - (Python 代码不在循环中工作)pandas.DataFrame.apply() 不在循环中工作

algorithm - BST中如何根据后继者获取节点的父节点?

python - 与其他排序算法相比,为什么插入排序如此之快?

c++ - 混淆测试fftw3——泊松方程2d检验

python - 如何通过数组交集对 pandas 数据框进行分组

python - 如何在defaultdict中有效地进行反向查找?

java - 匹配项目值(value)数量以尽可能接近价格点的算法(JAVA)