c++ - 确定两个其他值之间是否包含值的最有效方法

标签 c++ performance math

类似于Fastest way to determine if an integer is between two integers (inclusive) with known sets of values ,我想弄清楚某个值(很可能是 double float )是否介于两个其他值(相同类型)之间。需要注意的是,我不知道哪个值比另一个大,我正在尝试确定我是否应该/我应该如何避免使用 std::max/min。这是我已经尝试过测试的一些代码:

inline bool inRangeMult(double p, double v1, double v2) {
    return (p - v1) * (p - v2) <= 0;
}

inline bool inRangeMinMax(double p, double v1, double v2) {
    return p <= std::max(v1, v2) && p >= std::min(v1, v2);
}

inline bool inRangeComp(double p, double v1, double v2) {
    return p < v1 != p < v2;
}

int main()
{
    double a = 1e4;

    std::clock_t start;
    double duration;
    bool res = false;

    start = std::clock();
    for (size_t i = 0; i < 2e4; ++i) {
        for (size_t j = 0; j < 2e4; ++j) {
            res = inRangeMult(a, i, j) ? res : !res;
        }
    }
    duration = std::clock() - start;
    std::cout << "InRangeMult: " << duration << std::endl;

    start = std::clock();
    for (size_t i = 0; i < 2e4; ++i) {
        for (size_t j = 0; j < 2e4; ++j) {
            res = inRangeMinMax(a, i, j) ? res : !res;
        }
    }
    duration = std::clock() - start;
    std::cout << "InRangeMinMax: " << duration << std::endl;

    start = std::clock();
    for (size_t i = 0; i < 2e4; ++i) {
        for (size_t j = 0; j < 2e4; ++j) {
            res = inRangeComp(a, i, j) ? res : !res;
        }
    }
    duration = std::clock() - start;
    std::cout << "InRangeComp: " << duration << std::endl;

    std::cout << "Tricking the compiler by printing inane res: " << res << std::endl;
}

在大多数运行中,我发现使用 std::min/max 仍然是最快的(最新运行分别打印 346、310 和 324),但我不是 100% 确信这是最好的测试设置,或者我已经用尽了所有合理的实现方式。

如果有人提供更好的分析设置和/或更好的实现,我将不胜感激。

编辑:更新代码以使其不易被编译器优化。

第二次编辑:调整 a 的值和迭代次数。一次运行的结果是:

  • inRangeMult: 1337
  • inRangeMinMaz: 1127
  • inRangeComp:729

最佳答案

第一个测试:

(p - v1) * (p - v2) <= 0

由于算术运算,可能会导致上溢或下溢。

最后一个:

p < v1 != p < v2

不提供与其他结果相同的结果,这些结果包含边界 v1v2。考虑到 double 类型的范围和精度,这确实是一个很小的差异,但它可能很重要。

另一种选择是显式扩展第二个函数的逻辑:

p <= std::max(v1, v2) && p >= std::min(v1, v2)     // v1 and v2 are compared twice

像这样:

bool inRangeComp(double p, double v1, double v2) {
    return v1 <= v2                                // <- v1 and v2 are compared only once
        ? v1 <= p && p <= v2 
        : v2 <= p && p <= v1;
}

至少一个编译器(gcc 8.2),HERE (感谢 jarod42 的链接片段),似乎更喜欢这个版本而不是其他版本。

关于c++ - 确定两个其他值之间是否包含值的最有效方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54118163/

相关文章:

matplotlib - 绘制 Budyko 曲线 (1974)

c++ - 不同原始类型的乘法速度

c++ - 具有局部变量初始化延迟的 constexpr 函数

javascript - 使用 Emscripten 从 JavaScript 异步调用 C++ 函数

javascript - 在 jQuery : javascript template vs. 中高效克隆 html 追加 html,哪个性能更好?

math - 你如何在 Nimrod 中使用矩阵?

c++ - 在两个子类中使用基本乘法运算符

asp.net - 使用 Date 与 DateTime 时是否需要考虑性能或存储差异?

Java - 函数分析

java - 科学计算中如何处理下溢?