0

我在这里发现了两个关于 C/C++ 中快速和/或优雅的数字钳位的问题。C 专注于(可能是特定于平台的)优化:

钳制真实(固定/浮点)值的最快方法?

C ++之一也与C有关:

剪辑数字的最有效/优雅的方式?

但是,这些都没有提到它是否与就地操作有关,这对我来说似乎是一个至关重要的信息。这个问题是关于就地操作的。不同之处在于,如果数字在界限内,则无需进行写入操作。

在浏览有关钳位的答案时,大多数人只是建议使用三元变体,无论如何。我想知道为什么会这样?在速度和可读性方面,我都不清楚,特别是对于就地情况。我想了解是否有最佳实践,如果有,我会对理由感兴趣。

在我的示例代码中,有三个变体: 激活的变体 (1) 是我通常实现它的方式。变体 (2) 使用 anelse if并且变体 (3) 使用三元运算符。

根据在某些 i5 CPU 和 gcc 上的测量结果,-O3对于和,(1) 是最快的,(2) 和 (3) 显然更慢,并且彼此相比达到大致相同的速度。对于,所有变体都达到大致相同的速度。TYPEfloatdoubleint

我将这个问题明确标记为 C 而不是 C/C++,因为在后一种情况下——除了重复之外——人们会回答使用std::clamp或 Boost,这不是这个问题的想法。这是关于自己的独立于平台的无汇编实现的最佳实践,无论是在速度还是可读性方面

旁注,即使 C++: usingstd::clamp总是与最慢的变体相提并论。然而,很明显,这样的函数不能针对就地操作的特定情况进行优化,并且内联在这里没有帮助,因为它不会改变使用的指令。

#include <stdio.h>
#include <stdlib.h>

#define MY_MAX(a, b) (((a) > (b)) ? (a) : (b))
#define MY_MIN(a, b) (((a) < (b)) ? (a) : (b))

typedef float TYPE;

int main()
{
    const TYPE a = (TYPE) (rand() % 100);
    const TYPE b = a + (TYPE) (1 + rand() % 100);

    double sum = 0.0;

    for (unsigned int i = 0; i < 100000000; i++) {
        TYPE x = (TYPE) (rand() % 100);

#if 1
        if (x < a) x = a;        
        if (x > b) x = b;
#elif 0
        if (x < a) x = a;
        else if (x > b) x = b;
#elif 0
        x = MY_MAX(a, MY_MIN(b, x));
#endif

        sum += x;
    }

    printf("%lf\n", sum);

    return 0;
}
4

0 回答 0