How to use the PI constant in C++

2019-01-02 19:19发布

问题:

I want to use the PI constant and trigonometric functions in some C++ program. I get the trigonometric functions with include <math.h>. However, there doesn't seem to be a definition for PI in this header file.

How can I get PI without defining it manually?

回答1:

On some (especially older) platforms (see the comments below) you might need to

#define _USE_MATH_DEFINES

and then include the necessary header file:

#include <math.h>

and the value of pi can be accessed via:

M_PI

In my math.h (2014) it is defined as:

# define M_PI           3.14159265358979323846  /* pi */

but check your math.h for more. An extract from the "old" math.h (in 2009):

/* Define _USE_MATH_DEFINES before including math.h to expose these macro
 * definitions for common math constants.  These are placed under an #ifdef
 * since these commonly-defined names are not part of the C/C++ standards.
 */

However:

  1. on newer platforms (at least on my 64 bit Ubuntu 14.04) I do not need to define the _USE_MATH_DEFINES

  2. On (recent) Linux platforms there are long double values too provided as a GNU Extension:

    # define M_PIl          3.141592653589793238462643383279502884L /* pi */
    


回答2:

Pi can be calculated as atan(1)*4. You could calculate the value this way and cache it.



回答3:

You could also use boost, which defines important math constants with maximum accuracy for the requested type (i.e. float vs double).

const double pi = boost::math::constants::pi<double>();

Check out the boost documentation for more examples.



回答4:

Get it from the FPU unit on chip instead:

double get_PI()
{
    double pi;
    __asm
    {
        fldpi
        fstp pi
    }
    return pi;
}

double PI = get_PI();


回答5:

I would recommend just typing in pi to the precision you need. This would add no calculation time to your execution, and it would be portable without using any headers or #defines. Calculating acos or atan is always more expensive than using a precalculated value.

const double PI  =3.141592653589793238463;
const float  PI_F=3.14159265358979f;


回答6:

Rather than writing

#define _USE_MATH_DEFINES

I would recommend using -D_USE_MATH_DEFINES or /D_USE_MATH_DEFINES depending on your compiler.

This way you are assured that even in the event of someone including the header before you do (and without the #define) you will still have the constants instead of an obscure compiler error that you will take ages to track down.



回答7:

Since the official standard library doesn't define a constant PI you would have to define it yourself. So the answer to your question "How can I get PI without defining it manually?" is "You don't -- or you rely on some compiler-specific extensions.". If you're not concerned about portability you could check your compiler's manual for this.

C++ allows you to write

const double PI = std::atan(1.0)*4;

but the initialization of this constant is not guaranteed to be static. The G++ compiler however handles those math functions as intrinsics and is able to compute this constant expression at compile-time.



回答8:

From the Posix man page of math.h:

   The  <math.h>  header  shall  provide for the following constants.  The
   values are of type double and are accurate within the precision of  the
   double type.

   M_PI   Value of pi

   M_PI_2 Value of pi/2

   M_PI_4 Value of pi/4

   M_1_PI Value of 1/pi

   M_2_PI Value of 2/pi

   M_2_SQRTPI
          Value of 2/ sqrt pi


回答9:

Standard C++ doesn't have a constant for PI.

Many C++ compilers define M_PI in cmath (or in math.h for C) as a non-standard extension. You may have to #define _USE_MATH_DEFINES before you can see it.



回答10:

I would do

template<typename T>
T const pi = std::acos(-T(1));

or

template<typename T>
T const pi = std::arg(-std::log(T(2)));

I would not typing in π to the precision you need. What is that even supposed to mean? The precision you need is the precision of T, but we know nothing about T.

You might say: What are you talking about? T will be float, double or long double. So, just type in the precision of long double, i.e.

template<typename T>
T const pi = static_cast<T>(/* long double precision π */);

But do you really know that there won't be a new floating point type in the standard in the future with an even higher precision than long double? You don't.

And that's why the first solution is beautiful. You can be quite sure that the standard would overload the trigonometric functions for a new type.

And please, don't say that the evaluation of a trigonometric function at initialization is a performance penalty.



回答11:

I generally prefer defining my own: const double PI = 2*acos(0.0); because not all implementations provide it for you.

The question of whether this function gets called at runtime or is static'ed out at compile time is usually not an issue, because it only happens once anyway.



回答12:

I use following in one of my common header in the project that covers all bases:

#define _USE_MATH_DEFINES
#include <cmath>

#ifndef M_PI
#define M_PI (3.14159265358979323846)
#endif

#ifndef M_PIl
#define M_PIl (3.14159265358979323846264338327950288)
#endif

On a side note, all of below compilers define M_PI and M_PIl constants if you include <cmath>. There is no need to add `#define _USE_MATH_DEFINES which is only required for VC++.

x86 GCC 4.4+
ARM GCC 4.5+
x86 Clang 3.0+


回答13:

I just came across this article by Danny Kalev which has a great tip for C++14 and up.

template<typename T>
constexpr T pi = T(3.1415926535897932385);

I thought this was pretty cool (though I would use the highest precision PI in there I could), especially because templates can use it based on type.

template<typename T>
T circular_area(T r) {
  return pi<T> * r * r;
}
double darea= circular_area(5.5);//uses pi<double>
float farea= circular_area(5.5f);//uses pi<float>


回答14:

On windows (cygwin + g++), I've found it necessary to add the flag -D_XOPEN_SOURCE=500 for the preprocessor to process the definition of M_PI in math.h.



回答15:

C++14 lets you do static constexpr auto pi = acos(-1);



回答16:

You can do this:

#include <cmath>
#ifndef M_PI
#define M_PI (3.14159265358979323846)
#endif

If M_PI is already defined in cmath, this won't do anything else than include cmath. If M_PI isn't defined (which is the case for example in Visual Studio), it will define it. In both cases, you can use M_PI to get the value of pi.

This value of pi comes from Qt Creator's qmath.h.



回答17:

Values like M_PI, M_PI_2, M_PI_4, etc are not standard C++ so a constexpr seems a better solution. Different const expressions can be formulated that calculate the same pi and it concerns me whether they (all) provide me the full accuracy. The C++ standard does not explicitly mention how to calculate pi. Therefore, I tend to fall back to defining pi manually. I would like to share the solution below which supports all kind of fractions of pi in full accuracy.

#include <ratio>
#include <iostream>

template<typename RATIO>
constexpr double dpipart()
{
    long double const pi = 3.14159265358979323846264338327950288419716939937510582097494459230781640628620899863;
    return static_cast<double>(pi * RATIO::num / RATIO::den);
}

int main()
{
    std::cout << dpipart<std::ratio<-1, 6>>() << std::endl;
}


标签: