c++ - C++ 函数中的条件操作不会降低速度或代码重复:使用宏、内联函数、模板还是其他方式?
问题描述
我正在开发一些高性能的统计函数,并试图让它们根据一些函数参数执行不同的操作。目前的问题是开发一个通用代码,可以根据函数参数灵活地执行差分、部分/广义差分、增长率和对数差分。举一个基本的例子:
// General code to first-difference a vector:
std::vector<double> diff(std::vector<double> x, int ret = 1, double rho = 1, ...) { // ... = more arguments int l = x.size();
std::vector<double> res(l);
for (int i = 1; i < l; ++i) res[i] = FUN(x[i], x[i - 1]);
// rest of code ...
}
现在FUN(y, x)
是我想根据 和 的参数有效地改变的ret
东西rho
。对于简单的差异y-x
,对于广义差异y-rho*x
,对于对数差异log(y/x)
,对于增长率(y-x)*(100/x)
,并且可以添加更多选项。该代码适用于大型数据集并且需要快速,因此最佳情况下我会使用类似条件创建的宏的FUN
东西,例如:
std::vector<double> diff(std::vector<double> x, int ret = 1, double rho = 1, ...) {
int l = x.size();
std::vector<double> res(l);
#define FUN(y, x) (ret==1 && rho==1) ? ((y)-(x)) : \
(ret==1) ? ((y)-rho*(x)) : \
(ret==2) ? (log((y)/(x))) : \
(ret==3) ? ((y)-(x))*(100/(x))
for (int i = 1; i < l; ++i) res[i] = FUN(x[i], x[i - 1]);
}
这行得通,但是从降低的代码速度来看,在我看来,我不是有条件地创建宏,而只是一个宏,并且每次FUN
调用时,都会评估所有条件以执行正确的操作。我对这些预处理器命令(#if、#elif、#else、#endif、#define 和 #undef)进行了一些研究,但在我看来,您不能使用它们有条件地基于函数参数创建宏。第二种方法可能是使用内联函数,即:
inline double do_diff(double y, double x, double r) {
return y-x;
}
inline double do_gdiff(double y, double x, double r) {
return y-r*x;
}
inline double do_logdiff(double y, double x, double r) {
return log(y/x);
}
inline double do_growth(double y, double x, double r) {
return (y-x)*(100/x);
}
std::vector<double> diff(std::vector<double> x, int ret = 1, double rho = 1, ...) {
int l = x.size();
std::vector<double> res(l);
auto FUN = (ret==1 && rho==1) ? do_diff :
(ret==1) ? do_gdiff :
(ret==2) ? do_logdiff :
(ret==3) ? do_growth;
for (int i = 1; i < l; ++i) res[i] = FUN(x[i], x[i - 1], rho);
}
这里的问题只是它将代码速度降低了大约 1.5 倍。鉴于这些都是非常简单的操作,并且这段代码应该尽可能快,我宁愿避免这种情况。所以我的问题是:有什么方法可以改变执行的操作,而FUN
性能成本可以忽略不计?
注意:这里的代码重复是不可取的,因为我正在处理的实际代码要复杂得多,即它可以对无序的面板数据等执行迭代差异,大约 700 行在FUN
多个地方输入。
解决方案
模板似乎更合适:
template <typename F>
std::vector<double> diff(std::vector<double> x, F f, double rho = 1, ...) {
int l = x.size();
std::vector<double> res(l);
for (int i = 1; i < l; ++i) res[i] = f(x[i], x[i - 1], rho);
// ...
}
std::vector<double> diff(const std::vector<double>& x, ret = 1, double rho = 1, ...) {
switch (ret)
{
case 1: return (rho == 1) ?
diff(x, []{double y, double x, double r) { return y-x; }, rho) :
diff(x, []{double y, double x, double r) { return y-r*x; }, rho);
case 2: return diff(x, []{double y, double x, double r) { return log(y/x); }, rho);
case 3: return diff(x, []{double y, double x, double r) { return (y-x)*(100/x); }, rho);
}
throw std::runtime_error("Invalid argument");
}
似乎rho
只能由(一个)lambda 捕获,从而允许摆脱一个参数。
推荐阅读
- ruby-on-rails - 覆盖 ActiveAdmin 中的操作
- arrays - 通过 Google API 更新 Google Drive 中的 XML 文件
- c++ - GLSL Shader 没有渲染任何东西,VAO 被填充,VBO 被顶点填充
- cloudflare - Cloudflare Stream API Webhook 不工作
- javascript - 有没有办法命名同一个案例,但什么时候点击了 2 次?
- c++ - 我的程序在 Windows 机器上崩溃,但在 Linux 上运行良好
- python - Pyspark - 调用 pandas_udf 时出错,结果返回 Series.interpolate()
- python - 基于 x 轴上给出的新间隔的累积总和的阶梯图
- java - 如何在 Reactor 中将 Context 与 flatMap() 一起使用?
- azure - 如何识别 ADO Pipelines 中管道的 AzureDevOps id?