181
votes

There is a rather silly problem with the number pi in C and C++. As far as I know M_PI defined in math.h is not required by any standard.

New C++ standards introduced a lot of complicated math in the standard library - hyperbolic functions, std::hermite and std::cyl_bessel_i, different random number generators and so on and so forth.

Did any of the 'new' standards bring in a constant for pi? If not - why? How does all this complicated math work without it?

I am aware of similar questions about pi in C++ (they are several years and standards old); I would like to know the current state of the problem.

I am also very interested in why oh why C++ still doesn't have a pi constant but has a lot of more complicated math.

I know that I can define pi myself as 4*atan(1) or acos(-1) or double pi = 3.14;. Sure. But why do I still have to do it? How do standard math functions work without pi?

6
You note the existence of old questions such as Best platform independent pi constant?. If you worry they are out of date you could always set a bounty on one of them asking for answers based on C++17 etc... Then all the answers would be in one place. Why is still a good question but perhaps this should focus on why and asking for up to date should be a bounty on existing questions.Shafik Yaghmour
I think it may worth adding new answers since C++20 added a pi constant as far as I knowGuillaume Racicot
@GuillaumeRacicot i updated the question. Not sure if we should address C++20 since it's not officially out yet.Amomum
@GuillaumeRacicot: It’s a bit late to add one…Davis Herring
I want to note that pi is equal to arccos(-1), not arccos(1), but too few characters are changed for me to be able to edit the question.angleKH

6 Answers

116
votes

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

35
votes

Up to C++20, no, none of the standards introduced the constant that would represent the number pi (π). You can approximate the number in your code:

constexpr double pi = 3.14159265358979323846;

Other languages such as C# have the constant declared in their libraries.

Update: Starting with the C++20, there indeed is a pi constant declared inside the <numbers> header. It is accessed via: std::numbers::pi.

31
votes

As others said there is no std::pi but if you want precise PI value you can use:

constexpr double pi = std::acos(-1);

This assumes that your C++ implementation produces a correctly-rounded value of PI from acos(-1.0), which is common but not guaranteed.

It's not constexpr, but in practice optimizing compilers like gcc and clang evaluate it at compile time. Declaring it const is important for the optimizer to do a good job, though.

29
votes

M_PI is defined by "a standard", if not a language standard: POSIX with the X/Open System Interfaces extension (which is very commonly supported and required for official UNIX branding).

C++20, meanwhile, does have such constants (merged in the last round of C++20 features). Specifically, there is both std::numbers::pi (of type double) and a variable template that you can use if you want a different floating point type, e.g. std::numbers::pi_v<float>.

12
votes

It is not obviously a good idea because there is no obvious type with which define pi that is universally applicable across domains.

Pi is, of course, an irrational number so it cannot be correctly represented by any C++ type. You might argue that the natural approach, therefore, is to define it in the largest floating point type available. However, the size of the largest standard floating point type long double is not defined by the C++ standard so the value of the constant would vary between systems. Worse, for any program in which the working type was not this largest type, the definition of pi would be inappropriate since it would impose a performance cost on every use of pi.

It is also trivial for any programmer to find the value of pi and define their own constant suitable for use, so it does not provide any great advantage to include it in the maths headers.

-1
votes

Edited - To remove the term necessary, because it proved controversial. It is too much of an absolute term.

C++ is a large and complex language, for that reason the Standards Committee only include things which are strongly required. As much as possible is left to non-language standard libraries... like Boost.
boost::math::constants