我在一些Fortran代码中有以下行:
acc = acc + DRSite_t(u, k, s) * Exp(-(max(0.0_dp, t1 - real(s, dp)) / TAT(ds, k)))
其中DRSite_t
和TAT
都是数组而不是函数。
显然,如果DRSite_t
值为零,则不需要评估乘法运算符右侧的复杂计算。
现代编译器是否有可能接受并优化,或者我应该将其包装在if
块中?
或者这是我应该吮吸它并看到的情况?如果这有任何区别,我会使用gfortran,但是如果不同的编译器会以不同的方式处理事情,那将会很有趣。
答案 0 :(得分:4)
你的意思是,如果首先计算DRSite_t(u, k, s)
,检查它是否等于0然后可能会跳过表达式的其他部分?
我很确定编译器不这样做。在很多情况下,它会导致很多减速而不是加速。分支真的很贵。
我甚至认为,如果你手工完成,它会更慢,除非经常出现0。但编译器没有理由假设0经常发生。
答案 1 :(得分:3)
与往常一样,当浮点运算发生时,事情会变得有趣。在这种情况下,不确定0*expr
是否等同于0
。
在IEEE算术下考虑右侧表达式的可能性。我们可以得到:
-0
,对于支持带符号的零的负有限表达式; 0
,表示正有限值,或者当不支持带符号的零时的任何有限值。对于前两个,可能会设置标志,这可能会导致停止。
此外,如果expr
是函数引用,则该函数可能有副作用。
现在,在问题的情况下,程序员可能“知道”TAT
(如果一个函数)没有副作用并且是(严格地)正值并且那里的取幂具有正的有限结果。编译器必须绝对确定,或者知道程序员不关心。
如果TAT(ds,k)
无法证明(令编译器满意),那么在IEEE算法下,“优化”是错误的。
也就是说,编译器必须检查:
DRSite_t(u, k, s)
零;和这是很多努力,在一般情况下是不可行的。
总而言之,如果您确定0*expr
确实等同于0
,则值得考虑跳过整个赋值语句;但这对你来说是一个勇敢的编译器。如果TAT
是一个代价高昂且功能良好的函数,那么使这个条件赋值更好的最佳机会就是。