How to Use the Pi Constant in C++

How to use the PI constant in C++

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 */

Does C++11, 14, 17 or 20 introduce a standard constant for pi?

Up to and including C++17 pi is not a constant introduced into the language, and it's a pain in the neck.

I'm fortunate in that I use boost and they define pi with a sufficiently large number of decimal places for even a 128 bit long double.

If you don't use Boost then hardcode it yourself. Defining it with a trigonometric function is tempting but if you do that you can't then make it a constexpr. The accuracy of the trigonometric functions is also not guaranteed by any standard I know of (cf. std::sqrt), so really you are on dangerous ground indeed relying on such a function.

There is a way of getting a constexpr value for pi using metaprogramming: see http://timmurphy.org/2013/06/27/template-metaprogramming-in-c/


From C++20 some good news. There is a defininition for pi. C++20 adds some mathematical constants in <numbers>. For example std::numbers::pi is a double type.

Reference: https://en.cppreference.com/w/cpp/numeric/constants

Pi in C language

For printing a long double, use "%Lf". Use of "%lf" for long double causes undefined behavior.

#include <stdio.h>

int main()
{
long double pi = 22.0/7.0;
printf("%Lf\n", pi);
printf("%lf\n", pi);
return 0;
}

Output:

3.142857
0.000000

Update, in response to OP's comment

It's difficult to see the how accurately a number is represented using float, double, and long double using the default settings in printf. By using a format that prints more digits after the decimal point, the differences will be clearer.

Program:

#include <stdio.h>

void test1()
{
float pi = 22.0f/7.0;
printf("=== float ================\n");
printf("%.25lf\n", pi);
printf("%lf\n", pi);
}

void test2()
{
double pi = 22.0/7.0;
printf("=== double ===============\n");
printf("%.25lf\n", pi);
printf("%lf\n", pi);
}

void test3()
{
long double pi = 22.0L/7.0;
printf("=== long double ==========\n");
printf("%.25Lf\n", pi);
printf("%Lf\n", pi);
}

int main(void)
{
test1();
test2();
test3();
return 0;
}

Output:

=== float ================
3.1428570747375488281250000
3.142857
=== double ===============
3.1428571428571427937015414
3.142857
=== long double ==========
3.1428571428571428572357888
3.142857

Defining value of PI

#include <math.h>

const double PI = M_PI;

You can't call a function for a global const double because the constant needs to be evaluated at compile time. At runtime atan() could be anything. You could arrange for it to be called once at startup, but using an actual PI constant that's already available is better.

(actually using M_PI directly would also be good)

EDIT: It took many comment upvotes and re-reading my own answer over a year later to see why people were up in arms about my statement about constants. I was jumping over a step: As everyone is saying you can initialize const double at runtime just as easily as double. However, if you are using a global variable (instead of a constant expression) to store pi you will defeat some optimization opportunities. Some experiments with gcc suggest this isn't even as bad as I thought, which suggests a whole new question...

Defining a constant variable pi in a library

One reason to not put a constant in a header file is to avoid recompiling the code using the library (rather than just re-linking) if the constant changes. This reason doesn't apply to constants such as π that never change as a program is maintained.

There is an additional issue if the constant is a floating point value. C++ requires that floating point constants have storage assigned to them and that they be initialized in a .cpp file, not a .h file. This can makes them the constants less efficient than the equivalent inlined functions. This is why the Boost library uses inline functions. See this answer.

So for your case, the best bet is probably to use the Boost library, or if you don't want to take the dependency, to just make an inline function that does the same thing.

Best platform independent pi constant?

Meeting C++ has an article on the different options for generating pi: C++ & π they discuss some of the options, from cmath, which is not platform independent:

double pi = M_PI;
std::cout << pi << std::endl;

and from boost:

std::cout << boost::math::constants::pi<double>() << std::endl

and using atan, with constexpr removed since as SchighSchagh points out that is not platform independent:

 double const_pi() { return std::atan(1)*4; }

I gathered all the methods into a live example:

#include <iostream>
#include <cmath>
#include <boost/math/constants/constants.hpp>

double piFunc() { return std::atan(1)*4; }

int main()
{
double pi = M_PI;
std::cout << pi << std::endl;
std::cout << boost::math::constants::pi<double>() << std::endl ;
std::cout << piFunc() << std::endl;
}

C++2a pi_v

In C++2a we should get pi_v:

#include <numbers>
#include <iostream>

int main() {
std::cout<< std::numbers::pi_v<double> <<"\n";
}

Using M_PI with C89 standard

A conforming standard library file math.h is not only not required to, but actually must not define M_PI by default. In this context 'by default' means that M_PI must only get defined through compiler-specific tricks, most often undefined behavior through the use of reserved identifiers.

Just define the constant yourself (you can use the name M_PI freely, but should you want to be able to compile the code with a non-conforming compiler, you must first check that M_PI is not already defined). For convention's sake, do not define M_PI as anything other than (the approximation of) pi.



Related Topics



Leave a reply



Submit