重复相同计算的优化

Optimization of repeated identical computations

本文关键字:优化 计算      更新时间:2023-10-16

考虑以下两个函数:

std::pair<double,Vector> myMatrixOperation1(Matrix const& A, Vector const& V) {
    Vector AV = A*V;
    double norm_A_V = std::sqrt(dot(V,AV));
    return make_pair(norm_A_V,AV);
}
std::pair<double,Vector> myMatrixOperation2(Matrix const& A, Vector const& V) {
    return make_pair( norm(V,A) , A*V );
}
double norm(Vector const& V, Matrix const& innerProductMatrix) {
    double norm_A_V = std::sqrt(dot(V,innerProductMatrix*V));
}

它们显然做同样的事情,除了保证在第一个函数中只计算一次矩阵-向量乘积。

然而,第二个函数更容易读,因为它被重构,以便有一个完全的关注点分离:向量对任意内积的范数的概念被抽象成一个单独的函数。

现在的问题是,没有任何优化,矩阵向量乘积现在计算两次。

我的问题是:编译器是否足够聪明,只计算一次矩阵-向量乘积?如果是,我需要做什么?

我想至少我需要内联norm()函数。此外,关于算子*(矩阵常数&;A、向量常量;V)、懒惰的评价有什么帮助吗?(旁注:我正在使用特征库)

注意:我意识到一个类似的问题:编译器会优化重复的数学计算吗?然而,请注意,我的问题是编译器更难,因为操作符*(矩阵const&A、向量常量;V)不是内置的,因此编译器应该需要一些关于它的保证

编辑:

经过进一步的思考,这段引文来自维基百科(http://en.wikipedia.org/wiki/Optimizing_compiler):

例如,在某些语言中,函数不允许有副作用。因此,如果一个程序多次调用同一个函数使用相同的参数,编译器可以立即推断函数的结果只需要计算一次。在语言在允许函数有副作用的地方,另一种策略是可能的。优化器可以确定哪个函数没有边效果,并将此类优化限制为无副作用功能。只有当优化器有访问被调用的函数。

似乎编译器可以用第一个函数替换第二个函数,前提是operator+是纯的(即:没有副作用)。根据https://stackoverflow.com/a/5464114/1583122,在c++中,可以通过告诉编译器一个函数是constexpr,只有constexpr函数调用,并且有const参数来保证它的纯洁性。所以我认为编译器有可能保证这样的优化,只要满足一些要求。此外,请注意,c++ 14

中对constexpr函数的限制已经大大减少了。

如果在这段代码中优化速度很重要,我根本不会依赖编译器的行为。

即使一个聪明的编译器发现了这个技巧(我在这里表示怀疑,因为这涉及到相当多的语义洞察力——使函数内联可能会提示编译器),你也不能保证另一个编译器会看到它。甚至一个未来版本的相同!

经常出现这样的数值算法依赖于中间结果的重用。如果您清楚地注释为以后保留结果,我认为没有可读性问题。代码紧凑并不总是意味着代码的可读性。