操作员的表现| vs运营商+

时间:2011-06-01 19:38:49

标签: c++ math boolean-operations

|之间是否有任何重大差异和+会影响代码的长期性能?或者都是O(1)?我正在使用的代码是这样的:

uint64_t dostuff(uint64_t a,uint64_t b){
        // the max values of the inputs are 2^32 - 1

        // lots of stuff involving boolean operators
        // that have no way of being substituted by 
        // arithmetic operators

        return (a << 32) + b;
        //or
        return (a << 32) | b;
}

代码将被多次使用,所以我想尽可能加快速度。

8 个答案:

答案 0 :(得分:5)

任何现代计算机都没有性能差异。

这两个运营商虽然有不同的含义。如果该位已设置,|将不执行任何操作,但+将清除该位以及所有后续的非零位,并将下一个零位设置为1.

答案 1 :(得分:3)

两者肯定是O(1),因为O(1)表示常数。它们可能不是一样的常数。 Big Oh表示法意在理解与常数无关的渐近行为。

噢,是的,还有一件事。在优化之前始终配置文件。你很快就会发现时间没有花在你想到的地方。 始终

答案 2 :(得分:2)

使用|

+只能添加到操作时间明显的原因。

答案 3 :(得分:1)

两者都是一条指令。至于电子传播时间,不知道哪一个更快。

我猜你可以自己测试速度,但看到差异可能是线性的(如果可以检测到),并且受到噪声因素的影响,可能会有点困难。

答案 4 :(得分:1)

这里最好的答案不是试图预测哪一个更好,而是对其进行基准测试或检查汇编代码。我猜两个都将针对相同的指令进行优化,并且在任何情况下两者所采用的CPU周期数都可以相等。

但我强烈建议您检查ASM并对两种解决方案进行基准测试。

答案 5 :(得分:1)

如果有任何优势,那么它将支持or。然而,实际上,任何合理的现代CPU(甚至是真正的古代CPU)都不可能有任何差别。

基本上,or只是设置位,就是这样。只需要一个双输入or门,就可以获得一个传播延迟门。

加法器有点复杂:计算当前位需要三输入XOR。 XOR通常由两级门组成。此外,它还会生成一个进位,必须将其用作下一位加法器的输入。因此,“纹波进位加法器”需要与添加的位一样多的时钟周期。有一些更聪明的方法来处理这个问题,你处理的是与其余部分分开处理,所以你得到的传播延迟较低,但在最坏的情况下,即使这些也无济于事。

大多数情况只会影响您自己设计CPU的情况。如果您使用的是典型的CPU,功能单元中的门运行速度足够快,可以/将在一个时钟周期内完全添加。一些合理的近期甚至可以在一个功能单元中每个时钟周期进行两次添加。

答案 6 :(得分:0)

|和'+`是不同的数学运算 给出方程:

  unsigned int y = 2 + 2;
  unsigned int z = 2 | 2;

会产生不同的答案。

从技术上讲,`|'操作更快,因为它只在处理器内部使用OR门。加法操作需要更多门。

使用'|'获得的性能超过'+'通常会浪费在将数据输入和输出处理器所需的时间。换句话说,净绩效可以忽略不计。 (时差通常在纳秒范围内。)

但是,两种形式之间的维护时间可能更长。当一个人需要算术而不是比特琐事(反之亦然)时,试图找到这个运行时错误可能会很棒。

使用适当的操作符以达到正确的目的。让测试和维护小组休息一下。这种微优化是不值得的。

答案 7 :(得分:0)

这是特定于平台的(可能是特定于编译器的)。在PS3上的SPU上,如果我没记错的话,动态OR非常昂贵。我不确定数字,但我认为最终将它分成多个操作,导致成本扩展到几个指令。在x86 / x64或大多数现代CISC上,很可能一个只是一个指令,并且不太可能导致任何管道停顿或其他昂贵的操作。

编辑: 成本的原因是Cell处理器只有一个通用寄存器,这意味着它不能将两个变量加载到标准寄存器中并执行优化。相反,必须将值加载到必须进行操作的altivec寄存器集中,然后必须通过掩码将结果从altivec寄存器提取到gpr中,以便检索结果。

如果您要将这些操作推送到任何现代计算机上的PS3或GPU上,您可能需要了解这些处理器的行为方式。 GPU可能也有类似的问题,因为它们也是致力于SIMD操作的RISC处理器。