Question

A very common pattern in programming is to cap a value at a maximum after some kind of update. What I'd like to know, is if there's a difference between the following two pieces of code, and if one should be preferred:

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

vs

value += increment;

if (value > valueMax)
    value = valueMax;

My thinking is that this comes down to whether CPUs have instructions for taking two values and producing the minumum. If so, the call to std::min should result in this instruction and avoid an unnecessary branch. If not, the second version avoids an unnecessary assignment when value <= valueMax.

I'm not very good with this kind of thing, but I'm sure there's old-school assembly hackers who would know this. To them I ask: which is better?

Était-ce utile?

La solution

Modern compilers are smart enough to generate the same code in both cases. For example, 32-bit GCC generates:

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

64-bit Clang:

%1 = add nsw i32 %increment, %value
%2 = icmp sgt i32 %1, %valueMax
%value = select i1 %2, i32 %valueMax, i32 %1

Autres conseils

On VC10 on Release for the following code we have the following assembly:

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;
}

Generated:

  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]  

and

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  

So both cases optimized to either cmovge or cmovg instructions.

I would still go with std::min because it shows intent better than an if statement. It's optimized away and it's more readable.

The answer depends on the type of value. The code could be effectively optimized if all operations are fully transparent to the code optimizer, which would be the case if value is a plain integer. But your code would also compile if value is a std::string, and then the second version might be potentially faster since the assignment is conditional.

This should generally be much faster than branching:

int max(int x, int y) 
    { 
        return x ^ ((x ^ y) & -(x < y));  
    } 
};
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top