2

让我做非常快的循环,我必须确保在每个循环结束时变量aSOMEVALUE. 什么会更快?

if (a != SOMEVALUE) a = SOMEVALUE;

或立即做

a = SOMEVALUE;

它是浮点/整数/布尔/语言特定的吗?

更新:a是原始类型,而不是类。TRUE 比较的可能性是 50%。我知道算法是使循环快速的原因,所以我的问题也是关于编码风格的。

Update2:感谢大家的快速回答!

4

9 回答 9

2

在几乎所有情况下,仅设置值会更快。

当您必须处理与其他 cpu 共享缓存行时,或者如果“a”位于某种特殊类型的内存中时,它可能不会更快,但可以肯定的是,分支预测错误可能是比缓存共享更常见的问题。

此外 - 更小的代码更好,不仅用于缓存,还用于使代码易于理解。

如果有疑问 - 配置文件。

于 2012-07-19T14:46:33.313 回答
2

一般的答案是描述这类问题。但是,在这种情况下,可以进行简单的分析:

每个测试都是一个分支。每个分支都会导致轻微的性能损失。但是,我们有分支预测,并且这种惩罚会在一定程度上按时间摊销,具体取决于您的循环有多少次迭代以及预测正确的次数。

转换为您的情况,如果您在循环期间有很多更改,a那么使用的代码很可能if会在性能上更差。另一方面,如果值很少更新,则两种情况之间的差异将无限小。

不过,立即更改更好,应该使用,只要您不关心以前的值,如您的片段所示。

立即更改的其他原因:它会导致更小的代码,从而更好的缓存局部性,从而更好的代码性能。这是一种非常罕见的情况,更新a会使缓存行无效并导致性能下降。不过,如果我没记错的话,这只会在多处理器情况下对你造成影响,而且很少见。

请记住,在某些情况下,两者并不相似。比较NaNs 是未定义的行为。

此外,此注释仅处理 C 的情况。在 C++ 中,您可以拥有赋值运算符/复制构造函数比测试相等性花费更长的类。在这种情况下,您可能需要先进行测试。

考虑到您的更新,只要您确定不处理未定义的行为(浮点数),最好简单地使用赋值。编码风格也更好,更容易阅读。

于 2012-07-19T14:49:06.183 回答
1

你应该分析它。

我的猜测是差别不大,具体取决于测试为真的频率(这是由于分支预测)。

当然,只是设置它具有最小的绝对代码大小,这可以释放指令缓存以获得更有趣的代码。

但是,你应该再次分析它。

于 2012-07-19T14:44:28.587 回答
1

我会感到惊讶的是答案不是a = somevalue,但这个问题没有通用的答案。首先,它取决于复制速度与相等比较的速度。如果相等比较非常快,那么您的第一个选择可能会更好。其次,一如既往,它取决于您的编译器/平台。回答此类问题的唯一方法是尝试两种方法并为它们计时。

于 2012-07-19T14:46:26.607 回答
1

分析代码。相应地改变。

对于基本类型,无分支选项应该更快。例如,MSVS 不会优化分支。

话虽如此,这里有一个比较版本更快的例子:

struct X
{
    bool comparisonDone;
    X() : comparisonDone(false) {}
    bool operator != (const X& other) { comparisonDone = true; return true; }
    X& operator = (const X& other)
    {
       if ( !comparisonDone )
       {
           for ( int i = 0 ; i < 1000000 ; i++ )
               cout << i;
       }
       return *this;
    }
}

int main()
{
    X a;
    X SOMEVALUE;
    if (a != SOMEVALUE) a = SOMEVALUE;
    a = SOMEVALUE;
}
于 2012-07-19T14:51:22.457 回答
1

当您要求 C++ 程序时,我假设您正在将代码编译为本机机器指令。

在任何情况下,直接分配值而不进行任何比较应该会快得多。为了比较这些值,值 a 和 SOMEVALUE 都应该传送到寄存器,并且必须执行一条机器指令 cmp()。

但是在后一种直接分配的情况下,您只需将一个值从一个内存位置移动到另一个内存位置。

只有当内存写入比内存读取成本高得多时,分配才能变慢。我不认为会发生这种情况。

于 2012-07-19T14:50:13.003 回答
1

立即更改通常更快,因为它不涉及代码中的分支。

正如下面评论和其他人回答的那样,它确实取决于许多变量,但恕我直言,真正的问题是:你关心以前的值是多少?如果你是,你应该检查,否则,你不应该。

于 2012-07-19T14:43:36.140 回答
1

正如其他人所说,分析它将是最简单的判断方法,因为它在很大程度上取决于您向它提供的输入类型。但是,如果您考虑这两种算法的计算复杂性,您投入的输入越多,它们之间可能存在的差异就越小。

于 2012-07-19T14:47:33.220 回答
0

if实际上可以被一些编译器“优化掉”,基本上把它if变成代码噪音(对于正在阅读它的程序员来说)。

当我使用 GCC for x86 编译以下函数时(使用-O1,这是一个非常合理的优化级别):

int foo (int a)
{
  int b;

  if (b != a)
    b = a;

  b += 5;

  return b;
}

GCC 只是“优化”if 赋值 away,并简单地使用参数来做加法:

foo:
        pushl   %ebp
        movl    %esp, %ebp
        movl    8(%ebp), %eax
        popl    %ebp
        addl    $5, %eax
        ret
        .ident  "GCC: (GNU) 4.4.3"

有或没有if生成完全相同的代码。

于 2012-07-19T14:53:46.010 回答