How to use the PI constant in C++

1,343,156

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

Solution 2

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

Solution 3

C++20 std::numbers::pi

At last, it has arrived: http://eel.is/c++draft/numbers

main.cpp

#include <numbers> // std::numbers
#include <iomanip>
#include <iostream>

int main() {
    std::cout << std::fixed << std::setprecision(20);
    std::cout << "float       " << std::numbers::pi_v<float> << std::endl;
    std::cout << "double      " << std::numbers::pi << std::endl;
    std::cout << "long double " << std::numbers::pi_v<long double> << std::endl;
    std::cout << "exact       " << "3.141592653589793238462643383279502884197169399375105820974944" << std::endl;
}

where the exact result was calculated with:

echo "scale=60; 4*a(1)" | BC_LINE_LENGTH=0 bc -l

as per: How can I calculate pi using Bash command

Compile and run:

g++-10 -ggdb3 -O0 -std=c++20 -Wall -Wextra -pedantic -o main.out main.cpp
./main.out

Output:

float       3.14159274101257324219
double      3.14159265358979311600
long double 3.14159265358979323851
exact       3.141592653589793238462643383279502884197169399375105820974944

Tested on Ubuntu 20.04 amd64, GCC 10.2.0

The accepted proposal describes:

5.0. “Headers” [headers] In the table [tab:cpp.library.headers], a new <math> header needs to be added.

[...]

namespace std {
namespace math { 
 template<typename T > inline constexpr T pi_v = unspecified;
   inline constexpr double pi = pi_v<double>;

There is also a std::numbers::e of course :-) How to calculate Euler constant or Euler powered in C++?

These constants use the C++14 variable template feature: C++14 Variable Templates: what is their purpose? Any usage example?

In earlier versions of the draft, the constant was under std::math::pi: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p0631r7.pdf

Solution 4

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.

Solution 5

Get it from the FPU unit on chip instead:

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

double PI = get_PI();
Share:
1,343,156
Etan
Author by

Etan

SOreadytohelp

Updated on July 08, 2022

Comments

  • Etan
    Etan almost 2 years

    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?

  • Etan
    Etan over 14 years
    #define _USE_MATH_DEFINES followed by #include <math.h> defines M_PI in visual c++. Thanks.
  • Steve Jessop
    Steve Jessop over 14 years
    Good tip. If "you" are a compilation unit then of course you can ensure the macro is defined before anything is included. But if "you" are a header file, it's out of your control.
  • Matthieu M.
    Matthieu M. over 14 years
    In fact even if "you" are a compilation unit... depending on the ordering of the headers is a the shortest path toward maintenance nightmare...
  • Steve Jessop
    Steve Jessop over 14 years
    You don't have to depend on the ordering of the headers, though. It doesn't matter whether headers include each other, provided that you do the #define before you #include anything at all (at least, assuming that nothing #undefs it). Same applies to NDEBUG.
  • Dan Moulding
    Dan Moulding almost 14 years
    Boost: Boosting the already unnecessary complexity of C++ since 1999!
  • BuschnicK
    BuschnicK almost 14 years
    Catchy and partly true. On the other hand boost can be phenomenally useful at times...
  • Rob
    Rob about 13 years
    Works with cygwin headers as well.
  • kalu
    kalu almost 13 years
    This won't work if you want to define a global variable PI. You will get an error shouting that 'pi' is not declared in this scope. I am new to C++ so if there is a way to get around this I am not aware of it.
  • Richard J. Ross III
    Richard J. Ross III about 12 years
    You can always include cmath instead of math.h.
  • matiu
    matiu over 11 years
    For c++11 users: constexpr double pi() { return std::atan(1)*4; }
  • Thomas Eding
    Thomas Eding over 11 years
    -1: Works only if atan(1)*4 == 3.141592653589793238462643383279502884 (roughly speaking). I wouldn't bet on it. Be normal and use a raw literal to define the constant. Why lose precision when you don't need to?
  • Ben
    Ben over 11 years
    @ThomasEding - my math.h file reads #define M_PI 3.14159265358979323846 (if strict ANSI).
  • legends2k
    legends2k almost 11 years
    One can avoid the multiplication operation with atan2(0, -1);.
  • Sebastian Mach
    Sebastian Mach almost 11 years
    @DanMoulding: Uhm. Is C the only other language you know? Because all other languages I know, except C, have a standard library which is magnitudes bigger than C++' (e.g. Python, Haskell, C#, PHP, Delphi, Erlang, Java, ......). From personal experience, that elitist not gonna use libs-opinion is a pest and probably the number one reason for bad software written in C++.
  • Admin
    Admin almost 11 years
    @phresnel seriously, boost is the only reason why c++ can be as easily written as php with a massive relative performance increase, not to mention its children: json-spirit & websocket++.
  • Sebastian Mach
    Sebastian Mach almost 11 years
    @Gracchus: Yup. C++ without libraries (or without the new C++11 libraries) is, as much as I like that language and as much as I would like to code everything myself, not very productive.
  • R. Martinho Fernandes
    R. Martinho Fernandes over 10 years
    @matiu atan is not constexpr.
  • nacho4d
    nacho4d over 10 years
    This is a great example why we should not take this approach, we people make mistakes, rounding, copy&pasting, etc. I think using M_PI is the right approach.
  • legends2k
    legends2k over 10 years
    Even after defining _USE_MATH_DEFINES if GCC complains that's because __STRICT_ANSI__ is defined (perhaps you passed -pedantic or -std=c++11) which disallows M_PI to be defined, hence undefine it with -D__STRICT_ANSI__. When defining it yourself, since it's C++, instead of a macro you should constexpr auto M_PI = 3.14159265358979323846;.
  • legends2k
    legends2k over 10 years
    If one is doing this in C++11, make the const a constexpr.
  • m24p
    m24p over 10 years
    @nacho4d I too prefer M_PI if it's available, but not all systems are POSIX compliant. I think this approach is better than the 4*atan(1) method for the cases where M_PI is not available.
  • Timmmm
    Timmmm about 10 years
    I believe he said complexity not size. Presumably referring to a) the 3 nested namespaces, and b) defining pi as a templated function rather than just a normal constant.
  • user541686
    user541686 almost 10 years
    Try acos(-1) instead, no need for atan2.
  • developerbmw
    developerbmw almost 10 years
    Why is there a boost answer to almost every C++ question? Boost should be another language otherwise it pollutes C++
  • pqnet
    pqnet almost 10 years
    @Pharap almost nothing: the only difference is that using constexpr enforces the value to be computed at compile time, while the old const do that at program initialization.
  • Eugene Ryabtsev
    Eugene Ryabtsev almost 10 years
    It's often less CPU instructions and/or less latency to load an immediate operand than read an operand from a memory location. Also, only expressions that are known at compile-time could be pre-computed (I mean double x = pi * 1.5; and the like). If you ever intend to use PI in crunchy math in tight loops, you better make sure the value is known to the compiler.
  • Micah
    Micah over 9 years
    I usually use acos(-1), as you say, they are compile-time evaluated. When I tested M_PI, acos(-1) and atan(1)*4, I got identical values.
  • jimifiki
    jimifiki about 9 years
    @Pharap on my machine, with my compiler, atan(1)*4 generates pi at compile time. I'm not sure that this behavior is specified by the C++99 standard. Using constexpr is better.
  • Pharap
    Pharap about 9 years
    @jimifiki I've yet to have someone tell me that their compiler doesn't do this when using const but does with constexpr. If you can find one that doesn't, then and only then will you have something to refute my claim.
  • greggo
    greggo about 9 years
    @ThomasEding it really should. Especially acos(-1) should give the closest value to pi, since -1 is a special case for acos. Fun fact: let M_PI = pi-delta, (i.e. delta is the rounding error), then library call sin(M_PI) should return delta, with precision of a double. I.e. sin(M_PI) + M_PI, the two added together exactly using suitable means, should give you pi with 100+ significant bits -- if 'sin' is done properly. I've tried this with glibc and it worked.
  • meneldal
    meneldal about 9 years
    The very common issue in a project is that if you're compiling with Visual Studio for example you don't know in which order the compiler is going to go through your files so if you use <cmath> in different places it becomes a big pain (especially if it is included by another library you are including). It would have been much better if they put that part outside of the header guards but well can't do much about that now. The compiler directive works pretty well indeed.
  • Etan
    Etan almost 9 years
    :-) probably not that platform independent, but a nice additional exotic solution!
  • HelloGoodbye
    HelloGoodbye over 8 years
    @greggo: What data type are you using that has 100+ significant bits? And does "done properly" mean to calculate the exact value without any numerical error?
  • greggo
    greggo over 8 years
    @HelloGoodbye plain doubles. 52 bits in M_PI and 52 in sin(M_PI). If you add those together with full precision you get 100 good bits of pi. 'properly' just means that it should give the best result representable for the exact input value, even though the 'fuzz' in x at x = M_PI, multiplied by the derivative of sin(x) at that point (i.e. -1) gives you a 'fuzz' at the function output which of the same magnitude as sin(x). So, from one point of view the result is all fuzz and need not be that accurate, but a library function should still respect the exact input and give the best result.
  • greggo
    greggo over 8 years
    @HelloGoodbye specifically, the way I checked it was to obtain the values in python floats (which are 64-bit doubles), convert them to exact rational values with val.as_integer_ratio(), find the exact rational sum, and then print that out in decimal to as many places as needed using integer div and mod etc; then compare to published value of pi. Simpler way: you can just printf both original doubles using "%36.34f" and then add them on paper : 3.1415926535897931159979634685441852 + 0.0000000000000001224646799147353207
  • HelloGoodbye
    HelloGoodbye over 8 years
    @greggo You're right, I realized that the sin function only needs to calculate a value with as high precision as the data type allows. It sounds like an interesting trick in that case.
  • HelloGoodbye
    HelloGoodbye over 8 years
    @greggo But I'm wondering how you would construct a sin function that gives that kind precision? It wouldn't work with ordinary Maclaurin expansion, since you already after the two first terms will have a rounding error that is larger the desired precision if the argument is M_PI. But if you have found that the method you suggest works, the sin function you are using obviously does give that good precision, but how does it work?
  • greggo
    greggo over 8 years
    @HelloGoodbye it's done in the argument reduction. something like this: the sin function would start by reducing modulo pi, and it would use a extended accuracy value of pi for that. E.g. if you find that the input x is close to k * pi+x0, with x0 in +/- pi/2, you subtract k*MPI from it, and then you subtract k * pi0, where pi0 is the tiny difference between MPI and the true pi. So for x=MPI we have k=1, and the first subtraction gives exactly 0, and the second gives the more accurate residue. This also allows keeping accuracy with huge inputs like x= 1e20, where k is a really big number.
  • JAB
    JAB over 8 years
    @Timmmm You might want to complain to the C++ standards committee about (b), because the STL uses it too now (see std::numeric_limits, among other things).
  • Timmmm
    Timmmm over 8 years
    @JAB That is true, but at least it is only one nested namespace (and some of numeric_limits are constants rather than functions - I'm not sure why they used both approaches. Fortunately C++14 allows templated variables anyway so you could just do double d = std::pi; or whatever.
  • JAB
    JAB over 8 years
    @Timmmm Boost seems to favor nested namespaces in general. I've found it useful to just alias the namespaces when you need to (e.g. namespace bmc = boost::math::constants; or whatever). I wasn't aware that C++14 allows templated variables, though, that's interesting (though technically previous versions allowed them too, they just had to be members of specializations of template classes, hence why you have to use typename to tell your compiler a dependent type is actually a type [though I still can't see why compilers can't determine that for themselves in non-ambiguous cases]).
  • Nemo
    Nemo over 8 years
    "Calculating acos or atan is always more expensive" is not true. Any modern optimizing compiler knows all about standard math functions and can constant-propagate through them. See e.g. goo.gl/BvdJyr
  • 0xbadf00d
    0xbadf00d about 8 years
    Note that arg(log(x)) == π for all 0 < x < 1.
  • 0xbadf00d
    0xbadf00d about 8 years
    This is not an answer, but a comment to fritzone's answer.
  • 0xbadf00d
    0xbadf00d about 8 years
    You could also use boost .... Right, but please don't redefine an already defined constant (in a less flexible way).
  • Willy Goat
    Willy Goat about 8 years
    C++14, just do static constexpr auto pi = acos(-1); or just M_PI
  • 0xbadf00d
    0xbadf00d about 8 years
    std::acos is not a constexpr. So, your code won't compile.
  • Willy Goat
    Willy Goat about 8 years
    @0xbadf00d I compiled it with g++
  • Eivind Dahl
    Eivind Dahl almost 8 years
    With Visual Studio Community, I get an error using constexpr.
  • Ben Voigt
    Ben Voigt almost 8 years
    @0xbadf00d: It is a completely standalone answer that provides the steps needed to get M_PI working on a particular platform. That isn't a comment on an answer for some other platform any more that an answer for some other platform is a comment on this one.
  • Ben Voigt
    Ben Voigt almost 8 years
    @WillyGoat: Then g++ is wrong, because acos is not constexpr in C++14, and is not proposed to become constexpr even in C++17
  • Shital Shah
    Shital Shah almost 8 years
    Can the downvoter comment on what is wrong with this answer. This is well researched and tested and being in use in real system. I had definitely like to improve it if something is wrong.
  • Parker Coates
    Parker Coates over 7 years
    @Nemo, Counter example: godbolt.org/g/DsAern As has been said elsewhere, it appears only GCC does this currently and that's likely because it has declared the basic math functions as constexpr.
  • Remy Lebeau
    Remy Lebeau over 6 years
    FYI, Borland C++ compilers also define M_PI without needing _USE_MATH_DEFINES
  • Abderrahim Kitouni
    Abderrahim Kitouni over 6 years
    Good answer but the link is dead. I suggest this one instead.
  • VivienLeger
    VivienLeger about 6 years
    i love how you though out of the box here ;)
  • tobi_s
    tobi_s over 5 years
    The traditional way is to use 4*atan(1.): atan is easy to implement and multiplying by 4 is an exact operation. Of course, modern compilers fold (aim to fold) all constants with the required precision, and it's perfectly reasonable to use acos(-1) or even std::abs(std::arg(std::complex<double>(-1.,0.))) which is the inverse of Euler's formula and thus more aesthetically pleasing than it seems (I've added abs because I don't remember how the complex plane is cut or if that's defined at all).
  • Mariusz Jaskółka
    Mariusz Jaskółka over 5 years
    As of 2018, The answer should definetely be updated to use <cmath> instead of <math.h>
  • Grant Rostig
    Grant Rostig over 5 years
    Very nice. It might be necessary to have an "l" or "L" at the end of that number. I get a narrowing warning from my compiler gcc on linux.
  • Matt
    Matt about 5 years
    I love this answer. It is particularly useful when targeting older x86 platforms which is a small fad as of late where the optimizing compilers aren't as terribly involved as modern ones. Thanks for this Henrik!
  • user14717
    user14717 over 4 years
    @DanMoulding: The point of the boost::math::constants is that they are arbitrary precision constants. They can be used in (say) climate codes where quad precision is often required.
  • Kapten-N
    Kapten-N over 4 years
    @jaskmar I can't find an M_PI with <cmath> included. However, the answer should perhaps be updated to say M_1_PI instead, because that's the defined value that I can find with <math.h> included. There' also an M_2_PI, which is basically Tau.
  • wcochran
    wcochran over 4 years
    @BenVoigt are there any math functions that are constexpr? Apparently not: stackoverflow.com/questions/17347935/constexpr-math-function‌​s
  • Ben Voigt
    Ben Voigt over 4 years
    @wcochran: There are plenty of NEW math functions that are constexpr, see for example (github.com/kthohr/gcem). But they are not backward-compatible with the C functions of the same name, so they can't take over the old names.
  • Isaac Pascual
    Isaac Pascual about 4 years
    @0xbadf00d: It compile but you cant use it in a constexpr context
  • midjji
    midjji about 4 years
    Just so no one accidentally thinks you are serious (again-_-'). This is a terrible solution. The atan implementation is not defined by the standard meaning its implementation and possibly hw dependent. This means that the numerics can be terrible, meaning you may well be better off using 3.14 in general. Further its quite possibly slow, even for the special cases.
  • midjji
    midjji about 4 years
    This is a terrible idea. use a per type overloaded template constexpr, that way you get a compile error to force you to define it if a new type appears. Its also generally a terrible because the trig types are not limited to floating point types. So enjoy the atan(1) mistake... The standard does not guarantee that trigonometric functions compute their actual trigonometric values to the accuracy of the type. They generally do not, and it gets worse with e.g. fastmath and is always especially bad for the special values.
  • Elviss Strazdins
    Elviss Strazdins about 4 years
    @Pharap here you go: godbolt.org/z/UsGxf5. gcc is actually the only compiler that generates the constant at compile time. Visual Studio and clang does it at runtime by calling atan.
  • Jean-Claude Arbaut
    Jean-Claude Arbaut over 3 years
    @ElvissStrazdins Try icc.
  • Jeff Hammond
    Jeff Hammond over 3 years
    I had the obvious question "why not constexpr?" and someone already answered this on stackoverflow.com/questions/32814678/…, which might be useful to somebody.
  • Jeff Hammond
    Jeff Hammond over 3 years
    This is a GCC extension and should not be used (stackoverflow.com/questions/32814678/…).
  • Jack G
    Jack G over 3 years
    That's way more digits than you need. 3.1415927f is as accurate as you can store with 32bit floats, and 3.141592653589793 is as accurate as you can store with 64bit doubles.
  • Victor Eijkhout
    Victor Eijkhout over 3 years
    @WillyGoat You're proving my private rule about the use of "just": the acos is just as non-constexpr as atan so your suggestion does not work.
  • Anachronist
    Anachronist about 3 years
    I don't understand why the long double precision pi has only two more digits of accuracy than the double precision pi. That suggests that it's hardly worth using long double.
  • Ciro Santilli OurBigBook.com
    Ciro Santilli OurBigBook.com about 3 years
    @Anachronist good observation, I'm not too sure why this is the case, let me know if anyone figures it out, I'm lazy to think now :) Related: stackoverflow.com/questions/15176290/…
  • J. Tully
    J. Tully about 3 years
    Why is the float value so far off? 3.xxxxxx74101257324219 ? It should be 3.14159265f
  • Ciro Santilli OurBigBook.com
    Ciro Santilli OurBigBook.com about 3 years
    @J.Tully Google sugggests 7 figures is correct for 32-bit float: stackoverflow.com/questions/13542944/… I didn't stop to think myself though.
  • sappjw
    sappjw about 3 years
    @Kapten-N M_1_PI is 1/pi, not pi
  • Arnaud
    Arnaud about 3 years
    @Anachronist It could be a sign that on g++10, on your machine (like on mine), the long doubles are implemented as 80-bits extended precision, not quadruple precision.
  • Eric Postpischil
    Eric Postpischil over 2 years
    This is not a good solution since the standard headers will define π with a precision suitable for their C++ implementation. That is, they will use as many digits as needed to give π as accurately as the implementation is capable of. They may also use a hexadecimal format to avoid rounding issues in the conversion from decimal to the internal floating-point format. The standard headers should be preferred, and, if one is going to define π oneself, it would be with more digits.
  • Eric Postpischil
    Eric Postpischil over 2 years
    3.1415926535897932385 is a double constant. Accuracy is lost when converting the numeral to double, and converting that double to long double leaves the value unchanged, with the accuracy lost.
  • stackoverflowuser2010
    stackoverflowuser2010 over 2 years
    What exactly does a "C++ implementation" have to do with the number of digits of pi? Are you referring to the bit width of the registers?
  • stackoverflowuser2010
    stackoverflowuser2010 over 2 years
    This is literally the only good answer to the question. It doesn't include any esoteric header files, doesn't run any further math of trig operations, and doesn't rely on assembly code. It just uses good old fashioned American high school knowledge of math. Kudos, good sir!
  • stackoverflowuser2010
    stackoverflowuser2010 over 2 years
    @EricPostpischil: What's the answer, bro?
  • mabraham
    mabraham over 2 years
    It literally doesn't answer the question, which asked for a solution without defining it manually. It is also a path to frustration to introduce inconsistent definitions of constants within the same program.
  • Max Ostrowski
    Max Ostrowski over 2 years
    This does not provide an answer to the question. Once you have sufficient reputation you will be able to comment on any post; instead, provide answers that don't require clarification from the asker. - From Review
  • Konstantin Burlachenko
    Konstantin Burlachenko over 2 years
    I have upvote because during writing in C++ for 10+ years I have never seen the definition of pi, seems C++20 fixes the issue. "solution without defining it manually." - is stupid, you can do whatever you want. And I'm not sure it's under the responsibility of C to define any constant from the math of physics.
  • parsley72
    parsley72 about 2 years
    What if the value of Pi changes? You'll have to go back and edit it manually.