22

编程中一种非常常见的模式是在某种更新后将值设置为最大值。我想知道的是,以下两段代码之间是否有区别,是否应该首选:

value += increment;
value = std::min(value, valueMax);

对比

value += increment;

if (value > valueMax)
    value = valueMax;

我的想法是,这归结为 CPU 是否具有获取两个值并产生最小值的指令。如果是这样,对 std::min 的调用应该导致该指令并避免不必要的分支。如果不是,则第二个版本在 value <= valueMax 时避免不必要的赋值。

我不太擅长这种事情,但我敢肯定有老派的组装黑客会知道这一点。我问他们:哪个更好?

4

4 回答 4

14

现代编译器足够聪明,可以在两种情况下生成相同的代码。例如,32 位 GCC 生成:

addl    %esi, %edi
cmpl    %edx, %edi
movl    %edi, %eax
cmovgl  %edx, %eax

64 位 Clang:

%1 = add nsw i32 %increment, %value
%2 = icmp sgt i32 %1, %valueMax
%value = select i1 %2, i32 %valueMax, i32 %1
于 2013-03-21T05:44:49.207 回答
4

在以下代码的 VC10 上,我们有以下程序集:

int main(int argc, char *argv[])
{ 
  int dummyValue = 0, valueMax = 3000, value = valueMax + 1;

  cin >> valueMax;
  cin >> value;

  dummyValue = std::min(value, valueMax);

  cout << dummyValue;
  cin >> valueMax;
  cin >> value;

  if (value > valueMax)
    dummyValue = valueMax;

  cout << dummyValue;
  return 0;
}

生成:

  24:   dummyValue = std::min(value, valueMax);
00E112AF  mov         eax,dword ptr [valueMax]  
00E112B2  cmp         eax,dword ptr [value]  
00E112B5  lea         edx,[value]  
00E112B8  lea         ecx,[valueMax]  
00E112BB  cmovge      ecx,edx     // <-- this is our conditional assignment
00E112BE  mov         esi,dword ptr [ecx]  

if (value > valueMax)
  dummyValue = valueMax
00E112ED  mov         eax,dword ptr [valueMax]  
00E112F0  cmp         dword ptr [value],eax  
00E112F3  mov         ecx,dword ptr ds:[0E13038h]  
00E112F9  cmovg       esi,eax  

因此,这两种情况都针对任一cmovgecmovg指令进行了优化。

我仍然会选择,std::min因为它比if陈述更能显示意图。它经过优化,更具可读性。

于 2013-03-21T05:45:26.120 回答
0

答案取决于值的类型。如果所有操作对代码优化器完全透明,则可以有效地优化代码,如果 value 是纯整数,情况就是如此。但是如果 value 是 std::string,您的代码也会编译,然后第二个版本可能会更快,因为赋值是有条件的。

于 2013-03-21T08:24:52.540 回答
-2

这通常应该比分支快得多:

int max(int x, int y) 
    { 
        return x ^ ((x ^ y) & -(x < y));  
    } 
};
于 2020-03-14T06:30:30.423 回答