1

I am including math.h and cmath in my project. I am looking into the differences between math.h and cmath. I believe std::cos would use cmath, but some literature seems to suggest that may not be the case.

How can I specify to use cos function from math.h and not cmath?

#include <math.h>
#include <cmath>

...

double x;
int maxv = 1000000;
for(int i = 0; i < maxv; i++)
{
  x = static_cast<double>(i) / static_cast<double>(maxv);
  printf("diff = %lf\n", cos(x) - std::cos(x)); // math.h vs cmath
}
jdl
  • 6,151
  • 19
  • 83
  • 132
  • 3
    Which header file to include depends on your language. – Some programmer dude Jan 13 '23 at 17:22
  • 1
    If `cos()` is just drawn by a plain c header it should reside in the global namespace as `::cos()`. – πάντα ῥεῖ Jan 13 '23 at 17:23
  • 2
    I guess you could do `::cos()`, but I'm interested why you need this? Since both `std::cos()` and C `cos()` will probably be different names to same function. – sklott Jan 13 '23 at 17:23
  • we are using both libraries in our project, but depending on the flavor of linux we seem to get different values returned. So "cos" function may be picked from different libraries depending. So I want to compare the values within a small code, but need to invoke math.h over cmath, but not sure how – jdl Jan 13 '23 at 17:26
  • Could you post the code that shows how you are getting a different result? My guess here is that you are using different overloads. – Dietrich Epp Jan 13 '23 at 17:27
  • simply cos(x), again it depends on the flavor of linux choosing which library. – jdl Jan 13 '23 at 17:28
  • @jdl: Please post more surrounding code—what type does `x` have? – Dietrich Epp Jan 13 '23 at 17:29
  • What is the declaration for the variable `x`? What type does it have? – Dietrich Epp Jan 13 '23 at 17:36
  • added code to look at diff – jdl Jan 13 '23 at 17:36
  • C or C++. Can you pick one tag and remove the other please? – Wyck Jan 13 '23 at 17:40
  • removed the c tag – jdl Jan 13 '23 at 17:41
  • The real question is why do you feel the need to mix cmath and math.h. I'd focus on resolving that issue. – Taekahn Jan 13 '23 at 18:00
  • The C library `cos()` always takes and returns a `double`. The C++ [`std::cos()`](https://en.cppreference.com/w/cpp/numeric/math/cos) return type depends on the passed parameter. This might be why you see different values depending on which declaration is seen in different parts of your code. – Blastfurnace Jan 13 '23 at 18:02
  • @Blastfurnace more likely their values of `x`, being a double, are slightly different across different machines, i'd say. – Taekahn Jan 13 '23 at 19:28

2 Answers2

2

They are ordinarily the same function. The name of the library is libm (“m” for “math”), like many other Unix systems, and you get the same function whether you access that function through the <math.h> header or the <cmath> header.

The actual way these headers work is kind of complicated. I will say that in this case, you are probably just getting the ordinary cos function, no matter whether you call it through <math.h> as cos(x) or calling it through <cmath> as std::cos(x).

Assembly

Here’s a test function. You can paste this into Godbolt (https://gcc.godbolt.org/) and follow along.

#include <cmath>
double my_function(double x)
{
  return std::cos(x);
}

At -O2, this becomes:

my_function(double):
        jmp     cos

Here’s another test function:

#include <math.h>
double my_function(double x)
{
  return ::cos(x);
}

Here’s the result at -O2:

my_function(double):
        jmp     cos

It is exactly the same. You get exactly the same function either way. It is just a different interface.

More Tests

#include <math.h>
#include <cmath>
#include <cstdio>

int main(int argc, char **argv) {
  int maxv = 1000000;
  for(int i = 0; i < maxv; i++) {
    double x = static_cast<double>(i) / static_cast<double>(maxv);
    std::printf("diff = %f\n", cos(x) - std::cos(x));
  }
}

This prints diff = 0.000000 over and over again.

If you look at how the GCC optimizes this function, you’ll even see that it doesn’t actually call cos twice—it calls cos once, because it knows that the result will be the same both times. (It is unable to completely optimize out the call to cos, maybe because it does not successfully determine that the output to cos is finite in every loop iteration.)

Dietrich Epp
  • 205,541
  • 37
  • 345
  • 415
  • I like the assembly break down. But other than classes specifying which library to use, is there no way to open define where "cos(x)" is coming from? Because the code snippet cox(x)-std::cos(x) will always be referencing the same library being cmath in this case and the result will always be zero here. – jdl Jan 13 '23 at 19:04
  • @jdl: There are not multiple places for `cos` to come from. There is only one `cos`. It is like coming in a house through the front door or coming in through the window. It doesn't matter how you come in, it’s the same house. – Dietrich Epp Jan 13 '23 at 20:18
  • to piggy back on your analogy... yes there is one house, but if you come through the window on the third floor you might be a little tired and scraped up vs coming through the front door. So your value might be a little different. Other than declaring a class interface to each header, is there a way to choose my entrance into the house? – jdl Jan 13 '23 at 21:21
  • @jdl: Both options give you exactly the same result. What exactly are you trying to accomplish here? – Dietrich Epp Jan 14 '23 at 02:47
  • @DietrichEpp If you read the comments under the question, it looks like the real issue is that he is getting different answers on different computers. Like i said above, I think the the doubles and/or the math to obtain them are slightly different across different machines, as they are imprecise types. – Taekahn Jan 14 '23 at 03:38
  • @Taekahn: If someone is getting different answers on different computers, then that seems completely unrelated to the question, and the answer here. – Dietrich Epp Jan 14 '23 at 03:42
  • @Taekahn: This question is about the difference between `` and ``... and the problem is that, while there are differences between `` and ``, you will not get different results for `cos(x)` given a `double x;`, because there are not actually two different versions of `cos` being called, there is only one, and it is being called in the same exact way, with the same assembly code produced. – Dietrich Epp Jan 14 '23 at 03:44
  • @DietrichEpp I'm well aware of what the question is, and i upvoted your answer because it answers the question. I'm just answering _your_ question. " Both options give you exactly the same result. What exactly are you trying to accomplish here?" The reason why he isn't happy with your answer is because he wants the answer to a completely different question. He wants to know why the answer isn't the same across two different computers. – Taekahn Jan 14 '23 at 16:58
0

which library to perform cos x

Neither math.h nor cmath is a library. They are header files. They may be associated with a library, and may be considered part of a library product, but they are not the library. They declare functions the library provides and declare some additional things such as macros for constants and other things associated with the library.

I am including math.h and cmath in my project.

Do not do that. If you must do that, do not include them in the same files. In C files, use #include <math.h>. In C++ files, using #include <cmath>.

How can I specify to use cos function from math.h and not cmath?

The cos declared by math.h should be in the global namespace, so ::cos should refer to it. However, the global namespace is sometimes polluted, either by historical implementations of <cmath> that were sloppy or by programmer use of using namespace std. (The cos in <cmath> should be in the std namespace, so std::cos should refer to it.) If you must get the cos declared in <math.h>, you can define a routine in a C source file that calls cos and then call that C routine from your C++ code.

It is possible, even likely, these names will resolve to the same actual routine implementation.

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
  • Re: "historical implementations of `` that were sloppy" -- not really. Originally the C++ standard required that `` put the names **only** in `std`, and that `` put the names only in the global namespace. For implementations that don't control the underlying C headers this is unworkable, and the standard was changed to allow `` to also put names into the global namespace and `` to put nemes into `std`. – Pete Becker Jan 13 '23 at 18:39