Я пытался выбрать стандартный способ преобразования интегралов в строки, поэтому я продолжил и сделал небольшую оценку производительности измерение времени выполнения 3 методов
#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 convertion 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 типичный вывод (запуск Release в VS2013, который подразумевает флаг /O 2 optimizaiton), будет
Метод С++ 11......... 273
Метод струнного потока. 1923
Лексический метод литья... 222
UPDATE
В качестве альтернативы онлайновый запуск gcc с
g++ -std=c++11 -Ofast -march=native -Wall -pedantic main.cpp && ./a.out
С++ 11 метод......... 414
Метод струнного потока. 1538
Лексический метод литья... 275
Отказ от ответственности: результаты должны сравниваться между собой, а не между машинами.
Вопросы
1. Почему метод строкового потока последовательно худший (на порядок)? Должен ли он считаться устаревшим сейчас, когда появились более быстрые альтернативы?
2. Почему лексический литье последовательно лучше всего? Можно ли предположить, что это самая быстрая реализация?
Пожалуйста, не стесняйтесь настраивать и воспроизводить ваши версии этого кода. Буду признателен за эту тему.
PS
Код, который был фактически запущен, имел только одно измерение за main()
. Здесь все были представлены вместе, чтобы сэкономить место.
Флаги оптимизации - это спецификация компилятора или приложение. Я просто предоставляю блоки кода для выполнения тестов и ожидаю от SO-пользователей чипа с их результатами или предложениями о том, какая оптимальная конфигурация для каждого компилятора (для чего это стоило, я предоставил используемые здесь флаги).
Код работает для преобразования числовых строк в (требуется изменить тип v1
в main
). sehe сделал для double
(упомянутый в его комментарии к ответу). Это тоже неплохо поиграть с этим.