Should I use std:: when calling cmath functions?

226 views Asked by At

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
1

There are 1 answers

2
user17732522 On

Yes, you should include <cmath> and use std::. 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 the float overload of log10, while log10(i) uses the double overload.

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 of std::log10 available in the global namespace scope (but not necessarily in std::). So with only that include you should not use std::.

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 also std::. See support.c.headers.general in the current draft.

When you call the double overload, because your argument type and function return type are float, there needs to be a type conversion before and after the call, which is where the extra instructions come from.