假设我需要创建复杂的数学公式,例如
double f(double array1[100], double array2[100])
{
double z = array1[21] * array2[3] + array[10];
double q = array1[21] * array1[30] / array1[10];
return array1[1] * z * q;
}
或更复杂。我的解决方案是创建中间变量,如:
double f(double array1[100], double array2[100])
{
double energy = array1[21];
double mass = array2[3];
double speed = array[10];
double z = energy * mass + speed;
double q = energy * array[30] / speed;
return array1[1] * z * q;
}
问题是我并不真的需要这些新变量而且我不想浪费内存或增加时间来调用该函数。所以现在我正在为每个中间变量使用const
,所以编译器可能更容易优化它。但是使用引用可能更好吗?
答案 0 :(得分:5)
答案 1 :(得分:2)
gcc-llvm标准优化:结果相同,忽略指令重新排序
define double @_Z1fPdS_(double* nocapture %array1, double* nocapture %array2) nounwind readonly {
entry:
%0 = getelementptr inbounds double* %array1, i64 21 ; <double*> [#uses=1]
%1 = load double* %0, align 8 ; <double> [#uses=2]
%2 = getelementptr inbounds double* %array2, i64 3 ; <double*> [#uses=1]
%3 = load double* %2, align 8 ; <double> [#uses=1]
%4 = fmul double %1, %3 ; <double> [#uses=1]
%5 = getelementptr inbounds double* %array1, i64 10 ; <double*> [#uses=1]
%6 = load double* %5, align 8 ; <double> [#uses=2]
%7 = fadd double %4, %6 ; <double> [#uses=1]
%8 = getelementptr inbounds double* %array1, i64 30 ; <double*> [#uses=1]
%9 = load double* %8, align 8 ; <double> [#uses=1]
%10 = fmul double %1, %9 ; <double> [#uses=1]
%11 = fdiv double %10, %6 ; <double> [#uses=1]
%12 = getelementptr inbounds double* %array1, i64 1 ; <double*> [#uses=1]
%13 = load double* %12, align 8 ; <double> [#uses=1]
%14 = fmul double %13, %7 ; <double> [#uses=1]
%15 = fmul double %14, %11 ; <double> [#uses=1]
ret double %15
}
define double @_Z2f2PdS_(double* nocapture %array1, double* nocapture %array2) nounwind readonly {
entry:
%0 = getelementptr inbounds double* %array1, i64 21 ; <double*> [#uses=1]
%1 = load double* %0, align 8 ; <double> [#uses=2]
%2 = getelementptr inbounds double* %array2, i64 3 ; <double*> [#uses=1]
%3 = load double* %2, align 8 ; <double> [#uses=1]
%4 = getelementptr inbounds double* %array1, i64 10 ; <double*> [#uses=1]
%5 = load double* %4, align 8 ; <double> [#uses=2]
%6 = fmul double %1, %3 ; <double> [#uses=1]
%7 = fadd double %6, %5 ; <double> [#uses=1]
%8 = getelementptr inbounds double* %array1, i64 30 ; <double*> [#uses=1]
%9 = load double* %8, align 8 ; <double> [#uses=1]
%10 = fmul double %9, %1 ; <double> [#uses=1]
%11 = fdiv double %10, %5 ; <double> [#uses=1]
%12 = getelementptr inbounds double* %array1, i64 1 ; <double*> [#uses=1]
%13 = load double* %12, align 8 ; <double> [#uses=1]
%14 = fmul double %13, %7 ; <double> [#uses=1]
%15 = fmul double %14, %11 ; <double> [#uses=1]
ret double %15
}
答案 2 :(得分:1)
我开始通过const指针或const引用传递两个输入数组。
我不认为拥有像你的例子这样的函数是个好主意,我不知道它只是一个例子还是真正的代码。我认为性能上的差异非常小,而且创建易于阅读的代码要好得多。
回答您的问题:尽可能避免使用临时对象,因此请使用参考。如果逻辑上认为变量是const而不是出于性能原因,请使用const关键字。
在分析后立即提高速度。
答案 3 :(得分:1)
对于任何体面的编译器,我都非常怀疑它是否重要。
对于局部变量,如果你没有在任何地方获取变量的地址,编译器将能够看到它们仅在该函数中用作“临时”值并优化它们。他们几乎不会占用任何内存或生成任何不需要的代码。
我怀疑声明它们const会有所不同,如果你把它们作为参考,那么无论如何它们都必须是对“某事”的引用。
老实说,我根本不担心它,只需编写看起来最自然的代码,让编译器完成它的工作。
答案 4 :(得分:0)
如果在函数foreach上使用多个变量,则需要在堆栈中为它们分配空间,并且使用foreach,可能需要转到内存来获取值,使多个变量效率更低。 可能编译器足够聪明以避免不必要的内存读写,但是如果你不需要额外的变量就不要使用它,但是如果你的代码使用多个变量更加明确,则使用它们,因为编译器可能会使所有内容变得模糊不清
答案 5 :(得分:0)
我会稍微区别对待。
如果你想让它更具可读性,为什么不定义一些常量
static const unsigned int energy = 21;
static const unsigned int speed = 10;
static const unsigned int mass = 3;
double z = array1[energy] * array2[mass] + array[speed];
double q = array1[energy] * array1[30] / array1[speed];
return array1[1] * z * q;
可以全局定义索引变量。
1和30的值代表什么?
我看到还有另一个你没有定义的变量数组。