如果vs循环条件嵌套

时间:2012-03-22 12:53:00

标签: c++ performance visual-c++

我必须做一个比较,我想知道哪个更快。

1)

  for (i=0;i<4;i++){
     if (object1(i)==object2(i))
          retval = true;
     else { 
          retval = false;
          break;
     }
}

2)

 if ( (object1(0)==object2(0) && (object1(1)==object2(1) && (object1(2)==object2(2) && (object1(3)==object2(3)){
      retval = true;
 else
      retval = false;

或两者都表现相同?
谢谢你的建议

5 个答案:

答案 0 :(得分:2)

如果启用了优化标志,那么编译器可能会为这两个代码生成相同的机器指令,完全取消for循环,因为编译器已知确切的迭代次数:

顺便说一句,如果你非常关心,那么你可以这样写:

bool retValue = (object1(0)==object2(0)) && 
                (object1(1)==object2(1)) && 
                (object1(2)==object2(2)) && 
                (object1(3)==object2(3));

避免了:for循环,以及if-else分支,并且它不依赖于编译器优化。

答案 1 :(得分:2)

严格来说,最有效的途径是:

retval = object1(0) == object2(0) && object1(1) == object2(1).....

这基本上与你的循环相同,但不必将结果与true进行比较以确定条件的结果。

但是,我强烈建议保持循环,因为它更容易适应添加或删除数字。

答案 2 :(得分:2)

你需要衡量。但无论如何,第一个代码可以简化一点:

for (i = 0; i < 4; ++i)
    if (object1(i) != object2(i))
        return false;

return true;

现在选择更易读的形式。我会在这里选择循环,除非您已确认此代码导致性能问题。

答案 3 :(得分:0)

与优化一样,单一规则是 MEASURE

此外,我想编译器可能会以某种方式优化此代码(我和我甚至无法想象)。因此,我建议用最简单的可读形式编写它。

答案 4 :(得分:0)

我喜欢使用Try out LLVM和Clang页面:

struct Object {
  int operator()(int i) const;
};

bool loop(Object const& left, Object const& right) {
  bool retval = false;
  for (int i = 0; i < 4; i++) {
     if (left(i) == right(i) )
          retval = true;
     else { 
          retval = false;
          break;
     }
  }
  return true;
}

bool inlineif(Object const& left, Object const& right) {
  bool retval = true;
  if ( left(0) == right(0) &&
       left(1) == right(1) &&
       left(2) == right(2) &&
       left(3) == right(3))
      retval = true;
  else
      retval = false;
  return retval;
}

bool betterloop(Object const& left, Object const& right) {
  for (int i = 0; i < 4; ++i)
    if (left(i) != right(i))
        return false;

  return true;
}

bool betterif(Object const& left, Object const& right) {
  return left(0) == right(0) &&
         left(1) == right(1) &&
         left(2) == right(2) &&
         left(3) == right(3);
}

为循环生成以下IR(无论它们是如何编写的):

define zeroext i1 @_Z4loopRK6ObjectS1_(%struct.Object* %left, %struct.Object* %right) uwtable {
  br label %1

; <label>:1                                       ; preds = %7, %0
  %i.0 = phi i32 [ 0, %0 ], [ %8, %7 ]
  %2 = icmp slt i32 %i.0, 4
  br i1 %2, label %3, label %9

; <label>:3                                       ; preds = %1
  %4 = tail call i32 @_ZNK6ObjectclEi(%struct.Object* %left, i32 %i.0)
  %5 = tail call i32 @_ZNK6ObjectclEi(%struct.Object* %right, i32 %i.0)
  %6 = icmp eq i32 %4, %5
  br i1 %6, label %7, label %9

; <label>:7                                       ; preds = %3
  %8 = add nsw i32 %i.0, 1
  br label %1

; <label>:9                                       ; preds = %3, %1
  ret i1 true
}

两个if的非常相似的IR(所以我只给一个):

define zeroext i1 @_Z8betterifRK6ObjectS1_(%struct.Object* %left, %struct.Object* %right) uwtable {
  %1 = tail call i32 @_ZNK6ObjectclEi(%struct.Object* %left, i32 0)
  %2 = tail call i32 @_ZNK6ObjectclEi(%struct.Object* %right, i32 0)
  %3 = icmp eq i32 %1, %2
  br i1 %3, label %4, label %16

; <label>:4                                       ; preds = %0
  %5 = tail call i32 @_ZNK6ObjectclEi(%struct.Object* %left, i32 1)
  %6 = tail call i32 @_ZNK6ObjectclEi(%struct.Object* %right, i32 1)
  %7 = icmp eq i32 %5, %6
  br i1 %7, label %8, label %16

; <label>:8                                       ; preds = %4
  %9 = tail call i32 @_ZNK6ObjectclEi(%struct.Object* %left, i32 2)
  %10 = tail call i32 @_ZNK6ObjectclEi(%struct.Object* %right, i32 2)
  %11 = icmp eq i32 %9, %10
  br i1 %11, label %12, label %16

; <label>:12                                      ; preds = %8
  %13 = tail call i32 @_ZNK6ObjectclEi(%struct.Object* %left, i32 3)
  %14 = tail call i32 @_ZNK6ObjectclEi(%struct.Object* %right, i32 3)
  %15 = icmp eq i32 %13, %14
  br label %16

; <label>:16                                      ; preds = %12, %8, %4, %0
  %17 = phi i1 [ false, %8 ], [ false, %4 ], [ false, %0 ], [ %15, %12 ]
  ret i1 %17
}

这里的重要说明是br,它是分支指令。它可以用作简单的goto或边缘条件:

br i1 %11, label %12, label %16

表示如果i1为真,请转到label %12,否则转到label %16

似乎“自然”LLVM不会展开传统的循环版本,因此if版本在这里表现更好。实际上,我很惊讶它没有,我无法弄清楚为什么它不会......

所以,如果代码可能的内联速度要快一些,但是根据left(i) == right(i)(甚至那时)的成本,内联也可能不明显,因为CPU非常擅长分支预测。