尝试诊断 C++ 标准 for 循环与累积副作用之间的差异
Trying to diagnose difference between C++ standard for-loop and accumulate with side effects
我正在用 C++ 实现最大利润算法。
Find the Maximum Profit for a given stock trading day. Solution should be O(N) in Time and O(1) in Space requirements. You're allowed to purchase once in the day, and sell once in the day.
我最初是这样实现的:
int maxprofit_int(vector<int> const& v) {
int resProfit = 0;
int minPrice = v[0];
for (auto i = 1; i < v.size(); i++) {
auto price = v[i];
minPrice = min(minPrice, price);
auto profit = price - minPrice;
resProfit = max(resProfit, price);
}
return resProfit;
}
没有异常。
我心想 - “STL 通常 提供相同或更好的性能,那会是什么样子?”还有“我也可以制作这个通用的吗?”
template <class itr>
auto maxprofit_generic(itr begin, itr end) -> typename std::iterator_traits<itr>::value_type {
using v_t = typename iterator_traits<itr>::value_type;
return std::accumulate(next(begin, 1), end, v_t{0},
[minPrice = *begin](auto const& maximumProfit, auto const& price) mutable {
minPrice = std::min(minPrice, price);
auto const profit = price - minPrice;
return std::max(maximumProfit, profit);
});
}
accumulate 作为一个fold
操作,我使用容器的第一个值作为minPrice
,它可以在每次传递时更新。起始值始终与 return 值的类型相同。从我能收集到的所有信息来看,这两种算法实际上应该是相同的。
然而,将这两个带到快板凳上,我发现情况并非如此。在 GCC 10.1 和 Clang 10.0 中,使用 -O3,我发现整数版本和通用版本之间的运行时间 加倍 。我很难相信 Clang 和 GCC 有错误,所以我想知道为什么我的通用性能很糟糕。
有哪些提高通用版速度的建议?
我的 Quick-Bench 代码:
#include <vector>
#include <algorithm>
#include <numeric>
// Functions definitions removed for brevity
std::vector<int> uut = {1,2,4,1,3,5,2,5,7,9,3,4,5,5,5,7,9,9,4,2};
static void Maxprofit_Normal(benchmark::State& state) {
// Code inside this loop is measured repeatedly
for (auto _ : state) {
auto res = maxprofit(uut);
benchmark::DoNotOptimize(res);
}
}
// Register the function as a benchmark
BENCHMARK(Maxprofit_Normal);
static void Maxprofit_Generic(benchmark::State& state) {
// Code inside this loop is measured repeatedly
for (auto _ : state) {
auto res = maxprofit(uut.cbegin(),uut.cend());
benchmark::DoNotOptimize(res);
}
}
BENCHMARK(Maxprofit_Generic);
您的代码已进行基准测试,但未经过测试...
resProfit = max(resProfit, price);
应该阅读
resProfit = max(resProfit, profit);
此后两个版本运行以相同的速度更改。
我正在用 C++ 实现最大利润算法。
Find the Maximum Profit for a given stock trading day. Solution should be O(N) in Time and O(1) in Space requirements. You're allowed to purchase once in the day, and sell once in the day.
我最初是这样实现的:
int maxprofit_int(vector<int> const& v) {
int resProfit = 0;
int minPrice = v[0];
for (auto i = 1; i < v.size(); i++) {
auto price = v[i];
minPrice = min(minPrice, price);
auto profit = price - minPrice;
resProfit = max(resProfit, price);
}
return resProfit;
}
没有异常。
我心想 - “STL 通常 提供相同或更好的性能,那会是什么样子?”还有“我也可以制作这个通用的吗?”
template <class itr>
auto maxprofit_generic(itr begin, itr end) -> typename std::iterator_traits<itr>::value_type {
using v_t = typename iterator_traits<itr>::value_type;
return std::accumulate(next(begin, 1), end, v_t{0},
[minPrice = *begin](auto const& maximumProfit, auto const& price) mutable {
minPrice = std::min(minPrice, price);
auto const profit = price - minPrice;
return std::max(maximumProfit, profit);
});
}
accumulate 作为一个fold
操作,我使用容器的第一个值作为minPrice
,它可以在每次传递时更新。起始值始终与 return 值的类型相同。从我能收集到的所有信息来看,这两种算法实际上应该是相同的。
然而,将这两个带到快板凳上,我发现情况并非如此。在 GCC 10.1 和 Clang 10.0 中,使用 -O3,我发现整数版本和通用版本之间的运行时间 加倍 。我很难相信 Clang 和 GCC 有错误,所以我想知道为什么我的通用性能很糟糕。
有哪些提高通用版速度的建议?
我的 Quick-Bench 代码:
#include <vector>
#include <algorithm>
#include <numeric>
// Functions definitions removed for brevity
std::vector<int> uut = {1,2,4,1,3,5,2,5,7,9,3,4,5,5,5,7,9,9,4,2};
static void Maxprofit_Normal(benchmark::State& state) {
// Code inside this loop is measured repeatedly
for (auto _ : state) {
auto res = maxprofit(uut);
benchmark::DoNotOptimize(res);
}
}
// Register the function as a benchmark
BENCHMARK(Maxprofit_Normal);
static void Maxprofit_Generic(benchmark::State& state) {
// Code inside this loop is measured repeatedly
for (auto _ : state) {
auto res = maxprofit(uut.cbegin(),uut.cend());
benchmark::DoNotOptimize(res);
}
}
BENCHMARK(Maxprofit_Generic);
您的代码已进行基准测试,但未经过测试...
resProfit = max(resProfit, price);
应该阅读
resProfit = max(resProfit, profit);
此后两个版本运行以相同的速度更改。