c++cmathconstantsangle

Better/More Portable Method of Defining PI in C/C++?


Currently in one my scientific computation codes I have the following:

//Include M_PI constant
#define _USE_MATH_DEFINES
//Needed for square root function.
#include <math.h>

This works... on Linux at least... I have not tested it for C compilers on all platforms. However, when surveying some older Fortran codes, I recently came across this seemingly clever way of defining pi in another code (not my own):

<angle in deg.>*8.0d0 * datan(1.0d0) / 360.0d0

Of course this is perfectly feasible in C, right? So I could define my conversion function something like:

inline double DegToRad(const double A)
{
   return A * atan(1.0) / 45.0;
}

Which approach is more portable? Are there any numeric (e.g. rounding) considerations that would merit using one approach over another?

I do like that the M_PI constants make the code more readable. Of course, I could happily just assign my own PI constant using the above approach.

What is considered best practice in C/C++ codes that are going to be targeted at multiple platforms (Windows, Linux, etc.)?


Solution

  • Don't minimize the readability issue; personally, I'd do something like this:

    #ifndef M_PI
    // Source: http://www.geom.uiuc.edu/~huberty/math5337/groupe/digits.html
    #define M_PI 3.141592653589793238462643383279502884197169399375105820974944592307816406 
    #endif
    
    #define DEG_TO_RAD (M_PI/180.0)
    #define RAD_TO_DEG (180.0/M_PI)
    

    and then declare

    inline double DegToRad(const double deg) {
       return deg * DEG_TO_RAD;
    }
    
    inline double RadToDeg(const double rad) {
       return rad * RAD_TO_DEG;
    }
    

    This is probably not going to be any more or less portable (both atan and M_PI are standard in both C and C++). However it will be more readable than using atan and depending on your compiler's optimization settings, may save you a costly trig function call.

    UPDATE: It looks like M_PI isn't as standard as I thought. Inclusion of the #ifndef above should take care of the instances where it's not available.