我最近写了一个简短的算法来计算python中的happy numbers。这个程序允许你选择一个上限,它将决定它下面所有的快乐数字。为了进行速度比较,我决定将我所知道的算法从python直接翻译成c++。
令人惊讶的是,c++版本的运行速度明显慢于python版本。在发现前10000个快乐数字的执行时间之间进行的精确速度测试表明,python程序平均运行时间为0.59秒,而c++版本平均运行时间为8.5秒。
我将这种速度差异归因于这样一个事实:我必须为c++版本中的部分计算编写帮助函数(例如,确定元素是否在列表/数组/向量中),这些计算已经内置到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"
看起来像是按值将向量传递给其他函数。这将是一个明显的减速,因为程序实际上会在将向量传递给函数之前复制一个完整的向量。要解决这个问题,请传递对向量的常量引用,而不是副本。所以不是:
使用:
当您这样做时,您将无法再使用vector::iterator,因为它不是常量。您需要用vector::const_迭代器替换它。
也可以传入非常量引用,但在这种情况下,根本不需要修改参数。
有一个全新的、速度更快的版本,叫做a separate answer,所以这个答案被否决了。
我重写了你的算法,让它在找到快乐或不快乐的数字时进行缓存。我还试图使它尽可能像pythonic一样,例如通过创建单独的函数
digits()
和happy()
。很抱歉使用了Python3,但我也会展示一些有用的东西。这个版本要快得多。它以1.7s的速度运行,比原来的程序要快10倍(好吧,我的MacBook很老很慢:)
100000个元素,Python代码花费6.9秒,而C++最初占用了37秒。
我对代码进行了一些基本的优化,并设法将C++代码的速度提高了100倍。现在它在0.06秒内完成100000个元素。这比原来的C++代码快617倍。最重要的是在发布模式下编译,并进行所有优化。在调试模式下,这段代码实际上要慢几个数量级。
接下来,我将解释我所做的优化。
通过使用预先分配的数组而不是向量来优化代码是可能的,但这将是一项更大的工作,我将把它留给读者作为练习。:P页
下面是优化后的代码:
相关问题 更多 >
编程相关推荐