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

35,159

Solution 1

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

Solution 2

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.

Solution 3

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.

Solution 4

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>.

Solution 5

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.

Share:
35,159

Related videos on Youtube

Amomum
Author by

Amomum

Updated on July 23, 2022

Comments

  • Amomum
    Amomum almost 2 years

    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?

    • Shafik Yaghmour
      Shafik Yaghmour about 6 years
      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.
    • Guillaume Racicot
      Guillaume Racicot almost 5 years
      I think it may worth adding new answers since C++20 added a pi constant as far as I know
    • Amomum
      Amomum almost 5 years
      @GuillaumeRacicot i updated the question. Not sure if we should address C++20 since it's not officially out yet.
    • Davis Herring
      Davis Herring over 4 years
      @GuillaumeRacicot: It’s a bit late to add one…
    • angleKH
      angleKH almost 3 years
      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.
    • Amomum
      Amomum almost 3 years
      @angleKH nice catch after 3 whole years!
  • Deduplicator
    Deduplicator about 6 years
    You might want to add inline for C++17+.
  • Bathsheba
    Bathsheba about 6 years
    Ta. Have an upvote, but note that your definition is still vulnerable to imprecision with platforms with different definitions of double. C# has it easy since the double type is fixed. If I were on the C++ standards committee I'd propose something like std::constants<double>::pi
  • Lundin
    Lundin about 6 years
    As someone suggested, there's also const long double PI = acosl(-1.0L);.
  • Bathsheba
    Bathsheba about 6 years
    @Lundin: But that can't be a constexpr unfortunately, which is why I say "Defining it with a trig function is a pain "
  • Krupip
    Krupip about 6 years
    @Deduplicator isn't constexpr implicitly inline as well...?
  • Amomum
    Amomum about 6 years
    C++14 gave us variable templates. Isn't it what they are for?
  • R.. GitHub STOP HELPING ICE
    R.. GitHub STOP HELPING ICE about 6 years
    Why does it matter? Pi is a constant, not subject to change or anything implementation-specific. Just write out the value (in a const object if you like) to the number of places significant for double (or some ridiculous number if you care about hypothetical really-long long doubles).
  • Krupip
    Krupip about 6 years
    spoken like a true committee member, talk about all the ways it can't be done despite clear path forward being presented. See the suprisingly relevant example Variable Templates. I don't think your answer is bad, but I'm sure it wouldn't help Bjarne Stroustrup's eternal depression over the regret of handing control of C++'s future to a very indecisive committee.
  • Bathsheba
    Bathsheba about 6 years
    @R..The problem I have with that is what appears ridiculous now can become perfectly sane in 20 years time or so. (Bill Gates' 640k springs to mind). I trust Boost to keep up with architecture evolution.
  • R.. GitHub STOP HELPING ICE
    R.. GitHub STOP HELPING ICE about 6 years
    @Bathsheba: double is IEEE double on any reasonable implementation (and any where C conforms to Annex F; I'm not sure if C++ has an analogue but it should). There is no good reason to treat double as a type whose precision could vary. Use long double if you want that.
  • Bathsheba
    Bathsheba about 6 years
    @R. Fair enough, although you should static assert on std::numeric_limits<double>::is_iec559; in that case. Which, I confess, is what I have in my "master header". Note that formally you need to check all the floating point types separately. Just because one is IEEE754 doesn't mean they all are.
  • Deduplicator
    Deduplicator about 6 years
    @snb: For functions, and since C++17 which allowed it and introduced inline-variables, sure, constexpr implies inline. But namespace-level declarations didn't suddenly change their meaning.
  • user202729
    user202729 about 6 years
    Memorizing the value of pi is much easier than memorizing the formula. (although I have not attempted to memorize the formula at all...)
  • Konrad Rudolph
    Konrad Rudolph about 6 years
  • Bathsheba
    Bathsheba about 6 years
    @KonradRudolph - I thought it was in the 80s: based on the log of the number of cubes of 1 Planck length making up the observable universe. I wonder if anyone has a closer number? And I couldn’t help noticing that you’ve edited your comment; doubling the number! If you double it again you’re at where I’m at!
  • Konrad Rudolph
    Konrad Rudolph about 6 years
    @Bathsheba I only vaguely remembered, and updated the number when I found a reference.
  • Bathsheba
    Bathsheba about 6 years
    @KonradRudolph - which is a pitiful answer indeed: plenty of physics happens on a sub-proton scale. For now my Planck length cube argument holds and the quality of SO answers is evidently better than the ones on the fizzix site.
  • Konrad Rudolph
    Konrad Rudolph about 6 years
    @Bathsheba I don’t think a lot of physics (or any, actually) requires simultaneous precision at sub-proton and macroscopic (Universe) scale. In other words, the dynamic range in that (admittedly, not well written) answer is already exaggerated for all practical purposes. That said, I’m open to be told otherwise.
  • Bathsheba
    Bathsheba about 6 years
    @KonradRudolph: You’re absolutely correct but C++ prides itself on being a general purpose language, so if you need unusual floating point accuracy then it ought to be able to provide it. A lot of physics gets bogged down with the fact that Newton’s G is known to woeful precision.
  • supercat
    supercat about 6 years
    How much need would there be for pi, if the standard library included a set of trig functions measured angles in units of 2pi radians? While there are a few purposes involving derivatives, integrals, and differential equations, for which radians are useful, for most purposes involving actual angles they're just about the worst unit imaginable.
  • Bathsheba
    Bathsheba about 6 years
    @supercat: it pops up all over the place. Probability, financial mathematics, solutions using complex number libraries being some applications. C++ is a general purpose language and, as such, IMHO should have pi in its standard.
  • supercat
    supercat about 6 years
    @Bathsheba: Yeah, I guess radians end up being a natural unit for some kinds of operations on complex numbers because of Euler's equality, but it still irks me that there aren't any trig functions that are intended for use with actual angles. Having a graphics "rotate" transform use radians, for example, strikes me as just plain dumb, since likely as not the angle is going to be some multiple of pi/4, but rotating four times by pi/4 doesn't quite yield the original orientation.
  • Oliv
    Oliv about 6 years
    @snb constexpr does not imply inline for namespace scope variable [dcl.constexpr]: A function or static data member declared with the constexpr specifier is implicitly an inline function or variable
  • leftaroundabout
    leftaroundabout about 6 years
    @snb I agree that making pi a polymorphic constant is the clear path forward – in a language with Hindley-Milner type inference. In Haskell, we've always had pi :: Floating a => a, so that pi would automatically have the value 3.1415927 in a Float context, 3.141592653589793 in a Double context, and π in an symbolic-computation context. But would people really like having to explicitly instantiate the template parameter? Seems a bit awkward, especially if a fixed long double implementation would give identical results in most applications.
  • JAB
    JAB about 6 years
    @supercat You should be using quaternions for rotations anyway.
  • Shafik Yaghmour
    Shafik Yaghmour about 6 years
    There are several platform independent methods laid out here ... so while it would be nice to have a standardized one we do have options.
  • Deduplicator
    Deduplicator about 6 years
    Well, we could also have a new empty trivial type __exposition_pi_t with implicit conversion to all types of numbers.
  • Peter Cordes
    Peter Cordes about 6 years
    @KonradRudolph: A high-precision pi matters if implementing range-reduction. For example, x86/x87's internal Pi constant (full 64-bit mantissa) leads to a worst-case error for small inputs to the fsin instruction of "about 1.37 quintillion units in the last place, leaving fewer than four bits correct", and it's even worse for large inputs where range-reduction wraps around multiple times. This is somewhat tangential to constants used for long double in C++, but neat anyway.
  • Amomum
    Amomum about 6 years
    @leftaroundabout I believe writing auto a = pi<float>; is completely fine, certainly more readable then notorious 4*atan(1)
  • leftaroundabout
    leftaroundabout about 6 years
    @Amomum yeah... people would probably still use monomorphic shorthands locally to de-clunk mathematical formulas, but I agree that auto pi = std::pi<double> looks pretty clean.
  • user14717
    user14717 about 6 years
    @KonradRudolph: Numerical evaluation of functions and constants requiring 5000 decimal digits has been used with the PSQL algorithm to deduce insights into theoretical physics and reduce evaluation of multidimensional integrals to compile-time constants. See David Bailey's work on this. Boost.math computes pi dynamically unless it's in a list of precomputed types; this would be a requirement for any C++ standard value of pi.
  • emsr
    emsr about 6 years
    As a simple experiment, plot sin(pi*x) with pi specified to 16 digits for double. Watch the zeros of sin drift by x * epsilon(). It would be good to have sin_pi(), etc. but sometimes you just need pi because your problem doesn't present as x*pi. You might well need higher than working precision pi to prevent this aliasing. This could be implemented with constexpr expression templates for fundamental types. The pi object for fundamental types might be an unevaluated sum of the float type - a polynomial in epsilon() if you will.
  • emsr
    emsr about 6 years
    As an aside, I think all the basic math functions could have constexpr noexcept versions if the have error code returns (no write to global, and invariably ignored, errno). double sin(double x, error_code& ec); and auto [lgval, lgsign] = lgamma(x, ec);, etc.
  • Daniel Schepler
    Daniel Schepler about 6 years
    What about something like 0x3.243F6A8885A308D3p+0 which would make it absolutely clear how many bits of precision you're giving?
  • Chromatix
    Chromatix about 6 years
    I might argue that defining M_PI as a decimal constant to a "sufficient" number of digits would work nicely, without any of the problems you mention. Or, if typing is somehow a problem, then also define M_PI_F and M_PI_LD (with the latter specified for 128-bit implementations).
  • Amomum
    Amomum about 6 years
    Sure, std::hermite and std::cyl_bessel_i and std::cosh and std::mersenne_twister_engine and std::ranlux48 and std::cauchy_distribution and std::assoc_laguerre and std::beta all were absolutely necessary, we all use them every day!
  • Jeroen Mostert
    Jeroen Mostert about 6 years
    I'm pretty sure you couldn't get even the committee itself to sign off on the idea that everything they vote in is "absolutely necessary". It's not about necessity but about adding value to the language -- almost nothing in the standard library is necessary to write programs, and for that matter most of the core language can be tossed out as well (if you don't mind working in a Turing tarpit, that is). The value of the inclusion of a constant for pi can be debated, but the idea that it's not in there because it's just not necessary doesn't hold water.
  • BЈовић
    BЈовић about 6 years
    @DanielSchepler So, what is that "number" supposed to be? I didn't know there are double numbers with 16 base.
  • Tiger4Hire
    Tiger4Hire about 6 years
    Don't complain at me, I'm just quoting the standards committee. There were long open discussions about how much of boost should be included in the C++11 standard. The reason why such a small subset made it is because the compiler writers complained about how much testing was involved. Therefore, if something is in the standards, it's there because someone thought it necessary to standardise it. Just because you don't know why, doesn't mean there was no reason.
  • Cubic
    Cubic about 6 years
    If you absolutely need precision up to a particular number of digits, why are you using floating point numbers and not fixed?
  • Bathsheba
    Bathsheba about 6 years
    @Cubic: Floating point is very fast, and, so long as you know how they behave (error accumulation &c.) they are the perfect tool for many physical and financial modelling applications.
  • Amomum
    Amomum about 6 years
    @Tiger4Hire I'm sure there is reason for everything, I just can't understand why constant for pi was not added when a lot of more complex things were. Constant is easy to write with variable templates and won't require a lot of testing from compiler writers.
  • Tiger4Hire
    Tiger4Hire about 6 years
    @Amomum : Yes, adding pi seems like a small overhead for a big win. Mind, personally I'd prefer to see std::network before std::math::constants.
  • Nic
    Nic about 6 years
    Ugh, I downvoted this by misclick and now I can't undo it. Sorry. This deserves a +1 for a pretty good explanation of the committee's reasoning for why it hasn't been added, even if I personally think the reasoning is fundamentally flawed for the reasons people have already pointed out.
  • Ruslan
    Ruslan over 5 years
    Precision of π in Boost is actually in a funny situation: on the one hand we have this constant you cite, on the other we have this, which is due to a 7-year-old bug.
  • Arthur Tacca
    Arthur Tacca almost 5 years
    They could easily have added a function std::pi<T>() that is guaranteed to be defined for T being every possible floating. I'm not so familiar with the new-fangled constexpr idea, but presumably the function could be marked as that too.
  • cmaster - reinstate monica
    cmaster - reinstate monica almost 5 years
    This is dangerous because the acos() function has an infinite slope at x = -1. Consequently, this method relies on the acos() implementation to basically explicitly catch the case of a precise -1 argument, and return the correct constant directly. Better use something like 4*atan(1) which is mathematically much more robust (well-behaved slope at x = 1 and multiplication by 4 is always precise with floating point math).
  • BrandonL
    BrandonL almost 5 years
    Nobody is fortunate to use Boost
  • badola
    badola over 4 years
    We are not allowed to use std::acos in a constant expression. clang reports this as error. Kindly note that this is a non-conforming extension and should eventually be fixed in gcc. Kindly refer to this answer for more details.
  • Barry
    Barry over 4 years
    Feel free to reword my edit as you see fit - I just wanted to add the actual spelling of the new constants in here for posterity.
  • Don Hatch
    Don Hatch about 2 years
    @KonradRudolph yet another counterexample to the often-cited argument that 40 digits is enough for any computation to the accuracy you described... Consider computing the area of a relatively small spherical triangle on a relatively large sphere. If you do that in the familiar way, using spherical excess, you'll be adding three angles and then subtracting pi. Say it's a right triangle with legs 1e-20 (in units such that 1 is the sphere radius), then the answer will be about 0.5e-40. If your pi has only 40 digits, then your answer will have no good diglts.
  • Don Hatch
    Don Hatch about 2 years
    (and yes, there are certainly better ways to calculate spherical triangle area, but sometimes more digits of pi is the simplest and most expedient cannon to throw at the problem)