检查范围内容差的最快方法是什么?

时间:2012-12-04 04:15:45

标签: c++ algorithm optimization comparison

以下函数比较两个数组,如果考虑到容差,所有元素都相等,则返回true。

// Equal
template<typename Type>
bool eq(const unsigned int n, const Type* x, const Type* y, const Type tolerance)
{
    bool ok = true;
    for(unsigned int i = 0; i < n; ++i) {
        if (std::abs(x[i]-y[i]) > std::abs(tolerance)) {
            ok = false;
            break;
        }
    }
    return ok;
}

有没有办法打败这个功能的表现?

3 个答案:

答案 0 :(得分:2)

我会这样做,你也可以使用类函数滚动一个C ++ 03版本,它会更加冗长但应该同样有效:

std::equal(x, x+n, y, [&tolerance](Type a, Type b) -> bool { return ((a-b) < tolerance) && ((a-b) > -tolerance); }

主要区别在于放弃了abs:取决于Type以及如何实现abs,您可能会获得额外的条件执行路径,并且有很多分支错误预测,这当然应该避免这种情况。 a-b的重复计算可能会被编译器优化掉(如果认为必要的话)。

当然,它引入了对Type的额外运算符要求以及运算符&lt;或者&gt;很慢,它可能比abs慢(测量它)。

此外,std::equal是一个标准算法,为您完成所有循环和早期破坏,为此使用标准库总是一个好主意。它通常更好(至少在C ++ 11中)并且可以更好地进行优化,因为你清楚地显示了意图。

答案 1 :(得分:2)

在循环外计算abs(容差)。

您可以尝试将循环展开为“主要”循环和“次要”循环,其中“次要”循环仅跳转到其开头,“主要”循环具有“if”和“break”内容。在次要循环中执行ok &= (x[i]-y[i] < abstol) & (y[i]-x[i] < abstol);之类的操作以避免分支 - 请注意&而不是&&

然后部分展开并矢量化次循环。然后专门针对您实际使用的任何浮点类型,并使用平台的SIMD指令进行次循环。

在这样做之前,请考虑一下,因为它会增加代码大小,从而对可维护性产生不良影响,有时会影响系统其他部分的性能。

答案 2 :(得分:1)

您可以避免这些返回变量赋值,并预先计算容差的绝对值:

// Equal
template<typename Type>
bool eq(const unsigned int n, const Type* x, const Type* y, const Type tolerance) {
    const Type absTolerance = std::abs(tolerance);
    for(unsigned int i = 0; i < n; ++i) {
        if (std::abs(x[i]-y[i]) > absTolerance) {
            return false;
        }
    }
    return true;
}

另外,如果您知道公差总是可行的,则无需计算其绝对值。如果没有,你可以把它当作先决条件。