Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Best platform independent pi constant?

Tags:

c++

pi

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.

like image 452
Draugr Avatar asked Feb 18 '14 23:02

Draugr


2 Answers

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";
}
like image 131
Shafik Yaghmour Avatar answered Oct 12 '22 00:10

Shafik Yaghmour


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;
}
like image 28
Christopher Oicles Avatar answered Oct 11 '22 23:10

Christopher Oicles