вложенный, если против условия цикла - PullRequest
0 голосов
/ 22 марта 2012

Я должен сделать сравнение, и я хочу знать, что будет быстрее.

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 ]

2 голосов
/ 22 марта 2012

Строго говоря, наиболее эффективный путь будет:

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

Это в основном то же самое, что и ваш цикл, но не нужно сравнивать результат с true, чтобы определить результат условия.

Тем не менее, я настоятельно рекомендую сохранить цикл, поскольку гораздо проще адаптироваться для добавления или удаления чисел.

2 голосов
/ 22 марта 2012

Вам нужно измерить.Но в любом случае первый код можно немного упростить:

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

return true;

Теперь выберите более читаемую форму.Я бы выбрал этот цикл, если только вы не подтвердили наличие проблемы с производительностью, вызванной этим кодом.

2 голосов
/ 22 марта 2012

Если флаги оптимизации включены, то компилятор может выдавать одинаковые машинные инструкции для обоих кодов, полностью отменяя цикл for, поскольку компилятору известно точное число итераций:

Кстати, если вам так безразлично, вы могли бы написать это:

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

, что позволяет избежать обоих: forцикл, а также ветвь if-else, и это не зависит от оптимизации компилятора.

0 голосов
/ 22 марта 2012

Мне нравится играть со страницей Try 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
}

И очень похожий ИК для двух, если (поэтому я дам только один):

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) (и даже тогда), поскольку ЦП достаточно хороши для прогнозирования ветвлений.

0 голосов
/ 22 марта 2012

Как всегда с оптимизацией, одно-единственное правило - ИЗМЕРЕНИЕ .

Кроме того, я предполагаю, что компилятор мог оптимизировать этот код некоторыми способами, которые вы (и я) даже не могли себе представить. Поэтому я бы предложил написать его в наиболее читабельном виде.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...