我试图选择一个将积分转换为字符串的标准方法 http://codexpert.ro/blog/2014/04/14/standard-way-of-converting-between-numbers-and-strings-in-cpp11/,所以我继续做了一个小绩效评估 by 测量3种方法的执行时间 https://stackoverflow.com/a/21995693/2567683
#include <iostream>
#include <string>
#include <sstream>
#include <vector>
#include <chrono>
#include <random>
#include <exception>
#include <type_traits>
#include <boost/lexical_cast.hpp>
using namespace std;
// 1. A way to easily measure elapsed time -------------------
template<typename TimeT = std::chrono::milliseconds>
struct measure
{
template<typename F>
static typename TimeT::rep execution(F const &func)
{
auto start = std::chrono::system_clock::now();
func();
auto duration = std::chrono::duration_cast< TimeT>(
std::chrono::system_clock::now() - start);
return duration.count();
}
};
// -----------------------------------------------------------
// 2. Define the conversion functions ========================
template<typename T> // A. Using stringstream ================
string StringFromNumber_SS(T const &value) {
stringstream ss;
ss << value;
return ss.str();
}
template<typename T> // B. Using boost::lexical_cast =========
string StringFromNumber_LC(T const &value) {
return boost::lexical_cast<string>(value);
}
template<typename T> // C. Using c++11 to_string() ===========
string StringFromNumber_C11(T const &value) {
return std::to_string(value);
}
// ===========================================================
// 3. A wrapper to measure the different executions ----------
template<typename T, typename F>
long long MeasureExec(std::vector<T> const &v1, F const &func)
{
return measure<>::execution([&]() {
for (auto const &i : v1) {
if (func(i) != StringFromNumber_LC(i)) {
throw std::runtime_error("FAIL");
}
}
});
}
// -----------------------------------------------------------
// 4. Machinery to generate random numbers into a vector -----
template<typename T>
typename std::enable_if<std::is_integral<T>::value>::type
FillVec(vector<T> &v)
{
std::mt19937 e2(1);
std::uniform_int_distribution<> dist(3, 1440);
std::generate(v.begin(), v.end(), [&]() { return dist(e2); });
}
template<typename T>
typename std::enable_if<!std::is_integral<T>::value>::type
FillVec(vector<T> &v)
{
std::mt19937 e2(1);
std::uniform_real_distribution<> dist(-1440., 1440.);
std::generate(v.begin(), v.end(), [&]() { return dist(e2); });
}
// -----------------------------------------------------------
int main()
{
std::vector<int> v1(991908);
FillVec(v1);
cout << "C++ 11 method ......... " <<
MeasureExec(v1, StringFromNumber_C11<int>) << endl;
cout << "String stream method .. " <<
MeasureExec(v1, StringFromNumber_SS<int>) << endl;
cout << "Lexical cast method ... " <<
MeasureExec(v1, StringFromNumber_LC<int>) << endl;
return 0;
}
A 典型输出(在 VS2013 中运行 Release,这意味着 /O2 优化标志)将是
C++ 11 方法............ 273
串流法..1923
词法转换方法... 222
UPDATE
或者一个在gcc上在线运行 http://coliru.stacked-crooked.com/a/af7453e6b3d57ce1 with
g++ -std=c++11 -Ofast -march=native -Wall -pedantic main.cpp && ./a.out
C++ 11 方法........ 414
字符串流方法.. 1538
词法转换方法... 275
免责声明:结果应在彼此之间进行比较,而不是在机器之间进行比较
问题
1. 为什么字符串流方法始终是最差的(一个数量级)?既然出现了更快的替代方案,它是否应该被视为已弃用?
2. 为什么词法转换始终是最好的?我们可以假设这是最快的实现吗?
请随意调整和使用您的此代码版本。我很感激你对这个话题的见解。
PS
实际运行的代码每次只有一次测量main()
。为了节省空间,这里将 3 个一起展示。
优化标志是编译器特定的或应用程序强制的。我只是提供代码块来执行测试,并期望 SO 用户提供他们的结果或建议,以了解每个编译器的最佳配置是什么(对于它的价值,我提供了此处使用的标志)。
该代码适用于任何数字到字符串的转换(需要改变类型v1
in main
)。她这样做是为了double
(在他的回答评论中提到)。尝试一下也是个好主意。