This is a two-part question:
If I #include <cmath> in my header,
1 - What is the difference between using, say, std::log10() and log10()?
2 - Why do I get such a different assembly code for one vs the other? (being that std::log10() yields significantly less instructions)
Thanks!
#include <cmath>
float using_std(float i) {
return std::log10(i);
}
float not_using_std(float i) {
return log10(i);
}
Assembly (from godbolt)
using_std(float):
jmp log10f
not_using_std(float):
sub rsp, 8
cvtss2sd xmm0, xmm0
call log10
add rsp, 8
cvtsd2ss xmm0, xmm0
ret
I know these instructions are not "actual" assembly, they might be hiding more granular instructions, I just want to know if the difference I'm seeing is relevant to the actual performance of code.
Alright, this makes sense, if I instead #include <math.h>, they are the same:
using_std(float):
jmp log10f
not_using_std(float):
jmp log10f
Yes, you should include
<cmath>and usestd::. That way, you are guarantee that all overloads of the math functions for different argument types will be considered.What you are seeing is that
std::log10(i)uses thefloatoverload oflog10, whilelog10(i)uses thedoubleoverload.It isn't even guaranteed that
log10(i)will work at all if you only included<cmath>and it is unspecified which overloads will be declared in the global namespace scope by it.To guarantee that the global overload is available you need to include
<math.h>instead, which is guaranteed to make all overloads ofstd::log10available in the global namespace scope (but not necessarily instd::). So with only that include you should not usestd::.The standard recommends that only source files which need to also be valid ISO C should use the
<math.h>header and that other C++ sources should use the<cmath>header and consequently alsostd::. See support.c.headers.general in the current draft.When you call the
doubleoverload, because your argument type and function return type arefloat, there needs to be a type conversion before and after the call, which is where the extra instructions come from.