13

I know that you can use:

#define _USE_MATH_DEFINES

and then:

M_PI

to get the constant pi. However, if I remember correctly (comments welcome) this is compiler/platform dependent. So, what would be the most reliable way to use a pi constant that won't cause any problems when I port it from Linux to other systems?

I know that I could just define a float/double and then set it to a rounded pi value myself, but I'd really like to know if there is a designated mechanism.

Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740
Draugr
  • 436
  • 4
  • 11

2 Answers2

14

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";
}
Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740
  • Thanks, I think this is reliable enough for my needs. I'll think about integrating boost since I want to try some other of its features, anyway. – Draugr Feb 19 '14 at 00:14
  • @Draugr you can always try boost using some of the [online C++ compilers](http://stackoverflow.com/questions/3916000/online-c-compiler-and-evaluator) available, I added a live example to my answer as well. – Shafik Yaghmour Feb 19 '14 at 03:43
  • @SchighSchagh see [Is it a conforming compiler extension to treat non-constexpr standard library functions as constexpr?](http://stackoverflow.com/q/27744079/1708801) for more details. – Shafik Yaghmour Mar 04 '16 at 19:28
  • Is the `_v` part of `pi_v` the same as it in `is_same_v` and others probably meaning something like "value"? – Aykhan Hagverdili Mar 24 '20 at 17:10
3

The function below calculates pi without relying on any libraries at all.

Also, the type of its result is a template parameter.

Platform ueber-independence is stifled a bit because it only works with fixed-precision fractional types -- the calculated value needs to converge and remain constant over 2 iterations.

So if you specify some kind of arbitrary-precision rational or floating-point class which will automatically increase its precision as needed, a call to this function will not end well.

#include <iostream>
#include <iomanip>

namespace golf {
    template <typename T> inline T calc_pi() {
        T sum=T(0), k8=T(0), fac=T(1);
        for(;;) {
            const T next = 
                sum + fac*(T(4)/(k8+T(1))-T(2)/(k8+T(4))-T(1)/(k8+T(5))-T(1)/(k8+T(6)));
            if(sum == next) return sum;
            sum=next;
            fac /= T(16);
            k8  += T(8);
    }   }
    static const auto PI = calc_pi<double>();
}

int main() {
    std::cout << std::setprecision(16) << golf::PI << std::endl;
    return 0;
}
Christopher Oicles
  • 3,017
  • 16
  • 11