c++ 判断一个double函数是否为零的最快方法是什么

qyyhg6bp  于 2023-11-19  发布在  其他
关注(0)|答案(2)|浏览(193)

我正在重构一些代码,以提高处理大量浮点计算的性能(根据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
}


这似乎为我们节省了保存几个周期。然而,是否有更多的事情可以做,以加快速度,或者这是或多或少的门槛?

lzfw57am

lzfw57am1#

我认为这是最有效的了。启用优化后,在x86-64系统上,if的结果汇编为:

  1. movsd(将epsilon的值从全局常量存储器加载到寄存器中;函数变成了一个要加载的常量)
    1.一个andpd(屏蔽掉被检查的double中的负号位,这就是std::abs在内联时所要做的)
  2. comisd(比较两个寄存器)
  3. ja(实际的条件分支)
    前三条指令如果编译为更现代的芯片,则会更改为v前缀形式(我猜新版本在可用时会更有效),但其他方面不会更改。这是最便宜的。我想在理论上,如果你经常这样做,向量化可能会让你用更少的指令对多个值做同样的工作,但是:
    1.编译器可能会自己解决这个问题,
    1.如果没有,我会等到分析表明这是一个瓶颈,然后再进一步担心
    据我所知,任何基于std::fpclassify的解决方案(您希望FP_ZEROFP_SUBNORMAL被视为等效),例如:
switch (std::fpclassify(a)) {
case FP_SUBNORMAL:
case FP_ZERO:
    // do things
    break;
}

字符串
涉及相同的andpd指令,加上 * 三个 * comisd(或ucomisd)指令,以及 * 三个 * 条件跳转;两个额外的比较和条件分支几乎肯定比加载单个常量更糟糕。

velaa5lx

velaa5lx2#

你可以考虑的另一个优化是丢弃更多的案例:

constexpr float near_zero_limit = 0.01f;

if (std::fabs(a - b) < near_zero_limit )

字符串
这并不是说测试更快,而是有更多的情况下,你不做剩下的工作。我不知道你的算法,如果这对你的计算有意义,但你可以搜索最大的near_zero_limit,你可以考虑最终结果有效地为零或从零开始不可感知,如果这带来了更好的性能。

相关问题