C++ & π

published at 26.07.2013 14:41 by Jens Weller
Save to Instapaper Pocket

2 weeks ago, I had to refactor a bit of code, also containing pi (π). I do not often have to deal with mathematical C++ code, so using pi in my code is rare. But I wanted to replace #define PI 3.14 with something more useful. I discovered several ways of dealing with pi, which I'd like to compare now.

First, and most obvious, one could refactor the code to be a const variable:

const double pi = 3.14

Of course there is the option to add more digits, but this feels a bit like reinventing the wheel, is there a better source for pi, which already defines it in a suitable way? As C++ shares a few things with C, a look at <cmath> reveils that there is a define M_PI, that could do the job:

double pi = M_PI;
std::cout << std::setprecision(50)<< pi << std::endl;

This will give us pi with 48 digits (well, double), but in order to compile, we need to add a #define _USE_MATH_DEFINES before the include of <cmath>. With this move, our pi is now depending on the platform and the C standard. Its nice, but feels not quite the way you'd like to use things in C++. So, boost::math does a little work for you and defines a few math constants, which can be queryied over boost::math::constants:

std:: cout << boost::math::constants::pi<double>() << std::endl

This gives again the same result as above. Maybe boost is just hiding the c implementation here? Looking in the header, boost defines pi as:

BOOST_DEFINE_MATH_CONSTANT(pi, 3.141592653589793238462643383279502884e+00, "3.14159265358979323846264338327950288419716939937510582097494459230781640628620899862803482534211706798214808651e+00")

BOOST_DEFINE_MATH_CONSTANT hides a large template body, which specializes for float and double to return the second value of the define. Also to_string etc. are getting defined. So if you already use boost in your project, this is a nice way of getting pi, but using boost for this is maybe a bit of overkill.

But there is also a different idea of how to this, with C++11 we do have constexpr, so pi could be calculated at compile time:

constexpr double const_pi() { return std::atan(1)*4; }

Of course this will also work at runtime. Alternatively one can use std::atan2(0,-1), which saves a multiplication. But this code has one big problem: only GCC defines the mathfunctions like atan as constexpr. Which is a slight violation of the standard, as it does not define those functions to be constexpr. Having a constexpr version of atan and its relatives would allow for things like compiletime FFT, so it would be handy. The code at the end also links to a constexpr math function implementation under GPL. So, calculating PI at compiletime can be done in C++11!

Now whats best? This depends highly on your code, just defining pi is ok and works quite well nothing wrong with it. But if you switch numbers in pi, you'll get a hard to track error in your code. To redefine pi everywhere where you need it in your code isn't good either. Thats why M_PI or boost can offer an alternative, especially if you don't know pi from your head, so no need to look it up. Boost has another advantage: It works with types of multiple precision, as stated on reddit, and as you can see in the example of boost.multiprecision. The constexpr version fails, as std::atan & co aren't available as constexpr functions. Still, this would be useful when doing calculations at compiletime.

Join the Meeting C++ patreon community!
This and other posts on Meeting C++ are enabled by my supporters on patreon!