C++ calculating more precise than double or long double

I'm teaching myself C++ and on this practice question it asks to write code that can calculate PI to >30 digits. I learned that double / long double are both 16 digits precise on my computer.

I think the lesson of this question is to be able to calculate precision beyond what is available. Therefore how do I do this? Is it possible?

my code for calculating Pi right now is

#include "stdafx.h"
#include <iostream>
#include <math.h>
#include <iomanip>
using namespace std;

int main(){ 

    double pi;
    pi = 4*atan(1.0);
    cout<<setprecision(30)<<pi;
    return 0;
}

Output is to 16 digits and pi to 30 digits is listed below for comparison.

3.1415926535897931
3.141592653589793238462643383279

Any suggestions for increasing precision or is this something that won't matter ever? Alternatively if there is another lesson you think I should be learning here feel free to offer it. Thank you!


Solution 1:

You will need to perform the calculation using some other method than floating point. There are libraries for doing "long math" such as GMP.

If that's not what you're looking for, you can also write code to do this yourself. The simplest way is to just use a string, and store a digit per character. Do the math just like you would do if you did it by hand on paper. Adding numbers together is relatively easy, so is subtracting. Doing multiplication and division is a little harder.

For non-integer numbers, you'll need to make sure you line up the decimal point for add/subtract...

It's a good learning experience to write that, but don't expect it to be something you knock up in half an hour without much thought [add and subtract, perhaps!]

Solution 2:

You can use quad math, builtin type __float128 and q/Q suffixes in GCC/clang.

#include <stdio.h>

#include <quadmath.h>

int main ()
{
  __float128 x = strtoflt128("1234567891234567891234567891234566", nullptr);
  auto y = 1.0q;
  printf("%.Qf", x + y); // there is quadmath_snprintf, but this also works fine
  return 0;
}