Last active
April 17, 2020 13:10
-
-
Save onihusube/b772839e3da0712284cabf249d7a2d13 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#define _CRT_SECURE_NO_WARNINGS | |
#include <iostream> | |
#include <charconv> | |
#include <vector> | |
#include <random> | |
#include <chrono> | |
#include <type_traits> | |
#include <cassert> | |
#include <thread> | |
#include <numeric> | |
#include <string> | |
#include <string_view> | |
#include <sstream> | |
template<typename NumericType> | |
auto make_data(std::uint64_t N) -> std::pair<std::vector<char>, std::vector<std::string_view>> { | |
auto rng = []() { | |
if constexpr (std::is_integral_v<NumericType>) { | |
return std::uniform_int_distribution<NumericType>{}; | |
} | |
else if constexpr (std::is_floating_point_v<NumericType>) { | |
return std::uniform_real_distribution<NumericType>{}; | |
} | |
else { | |
static_assert([] { return false; }, "You have to specify a number type, right?"); | |
} | |
}(); | |
std::mt19937_64 urbg{ std::random_device{}() }; | |
std::vector<char> buffer(N * 21ull, '\0'); | |
auto* pos = buffer.data(); | |
std::vector<std::string_view> vec; | |
vec.reserve(N); | |
for (auto i = 0u; i < N; ++i) { | |
const auto num = rng(urbg); | |
const auto [end, ec] = std::to_chars(pos, pos + 21, num); | |
if (ec != std::errc{}) { | |
--i; | |
continue; | |
} | |
const std::size_t len = end - pos; | |
vec.emplace_back(pos, len); | |
pos += (len + 1); | |
} | |
return { std::move(buffer), std::move(vec) }; | |
} | |
template<typename Container> | |
void report(Container&& container) { | |
const auto first = std::begin(container); | |
const auto last = std::end(container); | |
const auto N = std::size(container); | |
using value_type = typename std::iterator_traits<std::remove_const_t<decltype(first)>>::value_type; | |
std::sort(first, last); | |
const auto max = *(last - 1); | |
const auto min = *first; | |
std::cout << "min : " << min.count() << " [ms]" << std::endl; | |
std::cout << "max : " << max.count() << " [ms]" << std::endl; | |
const auto medpos = first + (N / 2); | |
std::cout << "median : " << (*medpos).count() << " [ms]" << std::endl; | |
const auto sum = std::accumulate(first, last, value_type{}); | |
const auto ave = sum.count() / double(N); | |
std::cout << "average : " << ave << " [ms]" << std::endl; | |
const auto var = std::inner_product(first, last, first, 0ll, std::plus<>{}, | |
[](auto& lhs, auto& rhs) {return lhs.count() * rhs.count(); }) / N - (ave * ave); | |
std::cout << "stddev : " << std::sqrt(var) << "\n" << std::endl; | |
} | |
template<typename NumericType, typename F> | |
void profiling(const char* target, F&& func) { | |
using namespace std::chrono_literals; | |
constexpr int trialN = 10; | |
constexpr int sampleN = 1'000'000; | |
std::chrono::milliseconds results[trialN]{}; | |
for (int i = 0; i < trialN; ++i) { | |
//データの準備 | |
auto [buf, input] = make_data<NumericType>(sampleN); | |
//計測開始 | |
auto start = std::chrono::steady_clock::now(); | |
for (auto sv : input) { | |
func(sv); | |
} | |
//計測終了 | |
auto end = std::chrono::steady_clock::now(); | |
results[i] = std::chrono::duration_cast<std::chrono::milliseconds>(end - start); | |
std::this_thread::sleep_for(200ms); | |
} | |
std::cout << target << std::endl; | |
report(results); | |
} | |
int main() | |
{ | |
std::int64_t v; | |
profiling<std::int64_t>("to_chars() int64", [&v](auto sv) { | |
auto [ptr, ec] = std::from_chars(sv.data(), sv.data() + sv.length(), v); | |
if (ec != std::errc{}) throw new std::exception{}; | |
}); | |
profiling<std::int64_t>("stoll() int64", [&v](auto sv) { | |
v = std::stoll(std::string{ sv }); | |
}); | |
std::stringstream stm{}; | |
profiling<std::int64_t>("stringstream int64", [&stm, &v](auto sv) { | |
stm << sv; | |
stm >> v; | |
if (stm.fail()) stm.clear(); //エラー起きる原因分からん・・・ | |
}); | |
profiling<std::int64_t>("sscanf() int64", [&v](auto sv) { | |
auto r = sscanf(sv.data(), "%lld", &v); | |
if (r < 0) throw new std::exception{}; | |
}); | |
char* err{}; | |
profiling<std::int64_t>("strtoll() int64", [&v, &err](auto sv) { | |
v = strtoll(sv.data(), &err, 10); | |
if (sv.data() == err) throw new std::exception{}; | |
}); | |
double d; | |
profiling<double>("from_chars() double", [&d](auto sv) { | |
auto [ptr, ec] = std::from_chars(sv.data(), sv.data() + sv.length(), d); | |
if (ec != std::errc{}) throw new std::exception{}; | |
}); | |
profiling<double>("stod() double", [&d](auto sv) { | |
d = std::stod(std::string{ sv }); | |
}); | |
profiling<double>("stringstream double", [&stm, &d](auto sv) { | |
stm << sv; | |
stm >> d; | |
if (stm.fail()) stm.clear(); //エラー起きる原因分からん・・・ | |
}); | |
profiling<double>("sscanf() double", [&d](auto sv) { | |
auto r = sscanf(sv.data(), "%lg", &d); | |
if (r < 0) throw new std::exception{}; | |
}); | |
profiling<double>("strtod() double", [&d, &err](auto sv) { | |
d = strtod(sv.data(), &err); | |
if (sv.data() == err) throw new std::exception{}; | |
}); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment