Okay, I did a small test:
#include <iostream>
#include <algorithm>
int main(int argc, char** argv)
{
float a;
float b;
std::cin >> a;
std::cin >> b;
const float c = std::max(a, b); // option 1
const float c = a >= b ? a : b; // option 2
const float c = a < b ? b : a; // option 3
std::cout << c << std::endl;
return 0;
}
Option 1:
0000000000400790 <main>:
400790: 48 83 ec 18 sub $0x18,%rsp
400794: bf 80 0d 60 00 mov $0x600d80,%edi
400799: 48 8d 74 24 08 lea 0x8(%rsp),%rsi
40079e: e8 dd ff ff ff callq 400780 <std::istream& std::istream::_M_extract<float>(float&)@plt>
4007a3: 48 8d 74 24 0c lea 0xc(%rsp),%rsi
4007a8: bf 80 0d 60 00 mov $0x600d80,%edi
4007ad: e8 ce ff ff ff callq 400780 <std::istream& std::istream::_M_extract<float>(float&)@plt>
4007b2: f3 0f 10 44 24 0c movss 0xc(%rsp),%xmm0
4007b8: bf c0 0e 60 00 mov $0x600ec0,%edi
4007bd: f3 0f 5f 44 24 08 maxss 0x8(%rsp),%xmm0
4007c3: f3 0f 5a c0 cvtss2sd %xmm0,%xmm0
4007c7: e8 94 ff ff ff callq 400760 <std::ostream& std::ostream::_M_insert<double>(double)@plt>
4007cc: 48 89 c7 mov %rax,%rdi
4007cf: e8 9c ff ff ff callq 400770 <std::basic_ostream<char, std::char_traits<char> >& std::endl<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&)@plt>
4007d4: 31 c0 xor %eax,%eax
4007d6: 48 83 c4 18 add $0x18,%rsp
4007da: c3 retq
4007db: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1)
Option 2:
0000000000400790 <main>:
400790: 48 83 ec 18 sub $0x18,%rsp
400794: bf 80 0d 60 00 mov $0x600d80,%edi
400799: 48 8d 74 24 08 lea 0x8(%rsp),%rsi
40079e: e8 dd ff ff ff callq 400780 <std::istream& std::istream::_M_extract<float>(float&)@plt>
4007a3: 48 8d 74 24 0c lea 0xc(%rsp),%rsi
4007a8: bf 80 0d 60 00 mov $0x600d80,%edi
4007ad: e8 ce ff ff ff callq 400780 <std::istream& std::istream::_M_extract<float>(float&)@plt>
4007b2: f3 0f 10 54 24 0c movss 0xc(%rsp),%xmm2
4007b8: bf c0 0e 60 00 mov $0x600ec0,%edi
4007bd: 0f 28 ca movaps %xmm2,%xmm1
4007c0: f3 0f 10 44 24 08 movss 0x8(%rsp),%xmm0
4007c6: f3 0f c2 c8 02 cmpless %xmm0,%xmm1
4007cb: 0f 54 c1 andps %xmm1,%xmm0
4007ce: 0f 55 ca andnps %xmm2,%xmm1
4007d1: 0f 56 c1 orps %xmm1,%xmm0
4007d4: f3 0f 5a c0 cvtss2sd %xmm0,%xmm0
4007d8: e8 83 ff ff ff callq 400760 <std::ostream& std::ostream::_M_insert<double>(double)@plt>
4007dd: 48 89 c7 mov %rax,%rdi
4007e0: e8 8b ff ff ff callq 400770 <std::basic_ostream<char, std::char_traits<char> >& std::endl<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&)@plt>
4007e5: 31 c0 xor %eax,%eax
4007e7: 48 83 c4 18 add $0x18,%rsp
4007eb: c3 retq
4007ec: 0f 1f 40 00 nopl 0x0(%rax)
Option 3:
0000000000400790 <main>:
400790: 48 83 ec 18 sub $0x18,%rsp
400794: bf 80 0d 60 00 mov $0x600d80,%edi
400799: 48 8d 74 24 08 lea 0x8(%rsp),%rsi
40079e: e8 dd ff ff ff callq 400780 <std::istream& std::istream::_M_extract<float>(float&)@plt>
4007a3: 48 8d 74 24 0c lea 0xc(%rsp),%rsi
4007a8: bf 80 0d 60 00 mov $0x600d80,%edi
4007ad: e8 ce ff ff ff callq 400780 <std::istream& std::istream::_M_extract<float>(float&)@plt>
4007b2: f3 0f 10 44 24 0c movss 0xc(%rsp),%xmm0
4007b8: bf c0 0e 60 00 mov $0x600ec0,%edi
4007bd: f3 0f 5f 44 24 08 maxss 0x8(%rsp),%xmm0
4007c3: f3 0f 5a c0 cvtss2sd %xmm0,%xmm0
4007c7: e8 94 ff ff ff callq 400760 <std::ostream& std::ostream::_M_insert<double>(double)@plt>
4007cc: 48 89 c7 mov %rax,%rdi
4007cf: e8 9c ff ff ff callq 400770 <std::basic_ostream<char, std::char_traits<char> >& std::endl<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&)@plt>
4007d4: 31 c0 xor %eax,%eax
4007d6: 48 83 c4 18 add $0x18,%rsp
4007da: c3 retq
4007db: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1)
So, what we can see here is that option 1 and 3 are equal while 2 is inferior. One possible explantation is that most if not all STL algorithms require operator<()
for comparison and the GCC folks optimized for this (std::max()
is implemented that way, too). Or maybe there is something about IEEE 754 and SSE2 that distinguishes <
from >=
for some reason.
HTH
Flössie