我正在重构一些代码,以提高处理大量浮点计算的性能(根据valgrind,我们大约90%的时间都花在这个函数上,所以优化是好的);然而,如果我们遇到x
实际上为零的情况,那么我们可以直接分配零然后继续。以前我们做了以下事情(假设是内联函数):
if (std::fabs(a - b) < std::numeric_limits<double>::epsilon()) {
// do things
}
字符串
其中b = 0.0
在大多数情况下,而现在我移动以下模式,当我知道b
是零时:
if (std::abs(a) < std::numeric_limits<double>::epsilon()) {
// do things
}
型
这似乎为我们节省了保存几个周期。然而,是否有更多的事情可以做,以加快速度,或者这是或多或少的门槛?
2条答案
按热度按时间lzfw57am1#
我认为这是最有效的了。启用优化后,在x86-64系统上,
if
的结果汇编为:movsd
(将epsilon
的值从全局常量存储器加载到寄存器中;函数变成了一个要加载的常量)1.一个
andpd
(屏蔽掉被检查的double
中的负号位,这就是std::abs
在内联时所要做的)comisd
(比较两个寄存器)ja
(实际的条件分支)前三条指令如果编译为更现代的芯片,则会更改为
v
前缀形式(我猜新版本在可用时会更有效),但其他方面不会更改。这是最便宜的。我想在理论上,如果你经常这样做,向量化可能会让你用更少的指令对多个值做同样的工作,但是:1.编译器可能会自己解决这个问题,
1.如果没有,我会等到分析表明这是一个瓶颈,然后再进一步担心
据我所知,任何基于
std::fpclassify
的解决方案(您希望FP_ZERO
和FP_SUBNORMAL
被视为等效),例如:字符串
涉及相同的
andpd
指令,加上 * 三个 *comisd
(或ucomisd
)指令,以及 * 三个 * 条件跳转;两个额外的比较和条件分支几乎肯定比加载单个常量更糟糕。velaa5lx2#
你可以考虑的另一个优化是丢弃更多的案例:
字符串
这并不是说测试更快,而是有更多的情况下,你不做剩下的工作。我不知道你的算法,如果这对你的计算有意义,但你可以搜索最大的
near_zero_limit
,你可以考虑最终结果有效地为零或从零开始不可感知,如果这带来了更好的性能。