逻辑/关系表达式优化

Logical / Relational Expression Optimization

本文关键字:优化 表达式 关系 逻辑      更新时间:2023-10-16

我需要优化以下形式的表达式:

(a > b) || (a > c)

我尝试了几种优化的形式,其中一种如下:

(a * 2) > (b + c)

优化不是从编译器的角度出发的。我想把两个>减为一个

这是基于这样的假设,即1<a,b,c(<=26

然而,这只适用于某些情况。我想做的优化真的有可能吗?如果是的话,一开始会很有帮助。

答案可能是:您不想优化它。此外,我怀疑是否有任何方法可以更有效地写这篇文章。如果你说a、b和c的值在1到26之间,那么如果你想达到最佳(大小(,就不应该使用整数(你不需要那个精度(。

如果a>b,则无论如何都不会执行表达式a>c。因此,最多有2个(最少有1个(条件运算,这真的不值得优化。

我很怀疑这在大多数情况下是否是优化。

 a > b || a > c 

将评估为:

 compare a b
 jump not greater
 compare a c
 jump not greater

其中

 a * 2 > b + c

给出:

 shift a left 1 (in temp1)
 add b to c (in temp2)
 compare temp1 temp2
 jump if not greater

与性能一样,基于实际性能测量(最好是基于处理器体系结构的选择(进行决策总是要好得多。

我能想到的最好的是这个

char a, b, c;
std::cin >> a >> b >> c;
if (((b-a) | (c-a)) & 0x80) {
    // a > b || a > c
}

对于gcc -O2,这只生成一个条件分支

40072e:       29 c8                   sub    %ecx,%eax
400730:       29 ca                   sub    %ecx,%edx
400732:       09 d0                   or     %edx,%eax
400734:       a8 80                   test   $0x80,%al
400736:       74 17                   je     40074f <main+0x3f>

这利用了输入值的约束,因为这些值不能大于26,所以当a > b时,从b中减去a会给你一个负值,在2的补码中,你知道在这种情况下会设置位7c也是如此。然后我OR两者,使得位7指示是否为a > b || a > c,最后我们通过AND检查位7与0x80,并在其上分支。

更新:出于好奇,我选择了4种不同的编码方式。为了生成测试数据,我使用了一个简单的线性同余伪随机数生成器。我在一个循环中对它进行了1亿次迭代。为了简单起见,我假设如果条件为真,我们想在计数器上加5,否则就不做任何事情。我在使用-O2优化级别的Intel Xeon X5570 @ 2.93GHz上使用g++ (GCC) 4.6.3 20120306 (Red Hat 4.6.3-2)对其进行计时。

以下是代码(注释掉除一个条件变体外的所有条件变体(:

#include <iostream>
unsigned myrand() {
    static unsigned x = 1;
    return (x = x * 1664525 + 1013904223);
}
int main() {
    size_t count = 0;
    for(size_t i=0; i<100000000; ++i ) {
        int a = 1 + myrand() % 26;
        int b = 1 + myrand() % 26;
        int c = 1 + myrand() % 26;
        count += 5 & (((b-a) | (c-a)) >> 31);       // 0.635 sec
        //if (((b-a) | (c-a)) & 0x80) count += 5;     // 0.660 sec
        //if (a > std::max(b,c)) count += 5;          // 0.677 sec
        //if ( a > b || a > c) count += 5;            // 1.164 sec
    }
    std::cout << count << std::endl;
    return 0;
}

最快的是对我的回答中的建议进行修改,其中我们使用符号扩展来生成一个掩码,该掩码是321s还是320s,取决于条件是真还是假,并使用它来掩码正在添加的5,使其添加5或0。这种变体没有分支。时间在每行的注释中。最慢的是原始表达CCD_ 16。