39

How can I write a function which will return pi (π) to a given number of decimal places?

Speed is not a concern. I've been looking at http://bellard.org/pi/, but I still don't understand how to get the nth digit of pi.

the Tin Man
  • 158,662
  • 42
  • 215
  • 303
jmasterx
  • 52,639
  • 96
  • 311
  • 557
  • 11
    http://en.wikipedia.org/wiki/Pi is a good starting place. – Bill Apr 16 '10 at 16:54
  • 1
    Also, do you need to calculate Pi or simply format Pi? – Bill Apr 16 '10 at 16:56
  • you can look at Pi Computation record http://bellard.org/pi/pi2700e9/ just for fun.. – LB40 Apr 16 '10 at 18:41
  • 4
    In a convergent series with alternating positive and negative terms, the series will alternate above and below the target value. So you know from that that the value will always be between term n and term n+1. If term n and term n+1 match for their first k digits, then you know your target value to k digits. So in short, you get k digits of precision by stopping when the first k digits stop changing. (Non-alternating series work differently.) – Alan Apr 17 '10 at 04:41
  • 1
    More examples of this type of thing here: http://en.wikipedia.org/wiki/Convergent_series – Alan Apr 17 '10 at 04:42
  • Okay, do you want to be able to calculate pi using normal computer arithmetic, or do you want to calculate pi to more precision than is usually available (IEEE 64-bit float)? – David Thornley Aug 11 '10 at 21:30
  • There is no known efficient method to compute the Nth *decimal* digit of π without computing all the previous. –  Oct 11 '21 at 09:02
  • An easy and decent method for a small number of decimals (say thousands): 16 arctan(1/5)-4 arctan(1/239), where the arc tangent is computed by Taylor. –  Oct 11 '21 at 09:07

11 Answers11

31

In calculus there is a thing called Taylor Series which provides an easy way to calculate many irrational values to arbitrary precision.

Pi/4 = 1 - 1/3 + 1/5 - 1/7 + ...
(from http://www.math.hmc.edu/funfacts/ffiles/30001.1-3.shtml )

Keep adding those terms until the number of digits of precision you want stabilize.

Taylor's theorem is a powerful tool, but the derivation of this series using the theorem is beyond the scope of the question. It's standard first-year university calculus and is easily googlable if you're interested in more detail.


I didn't mean to imply that this is the most practical method to calculate pi. That would depend on why you really need to do it. For practical purposes, you should just copy as many digits as you need from one of the many published versions. I was suggesting this as a simple introduction of how irrational values can be equated to infinite series.

the Tin Man
  • 158,662
  • 42
  • 215
  • 303
Alan
  • 4,897
  • 2
  • 24
  • 17
  • What happens when I want to go pas the limit of int64 (double) ? – jmasterx Apr 16 '10 at 17:10
  • Also, how can I tell to what accuracy I receive ex: 1 decimal per 500 iterations.... – jmasterx Apr 16 '10 at 17:13
  • 31
    This taylor series is probably one of the worst ways to generate PI on a computer. You have to have huge precision on your calculations and it'll take many billions of iterations to get past 3.14159. Go ahead, try and see. Or here's a web site that talks about it: http://www.cygnus-software.com/misc/pidigits.htm – indiv Apr 16 '10 at 17:51
  • I remember writing this in C++ and QuickBasic and discovering the QuickBasic version actually generated PI faster :/ – NibblyPig Apr 16 '10 at 17:58
  • on x86 (x87 actually) use a type long double. This is a 10 byte number. You can also use a BigDecimal-like class. Interestingly enough, x86 has the instructions `fldpi` that loads pi into the fpu and `fstp tword MEM_LOC` can be used to store to a 10 byte memory location. – KitsuneYMG Apr 16 '10 at 18:00
  • 2
    @kts: That still doesn't change the fact that you need **billions** of iterations for any reasonably accurate answer. – Billy ONeal Apr 16 '10 at 18:12
  • 6
    @user146780: Simple. Notice that the terms are getting successively smaller and are alternately added and subtracted. So when you add a term, you are **certainly** above the real **π**. When you subtract, you are certainly below. So the last two partial sums provide an upper and lower bound for the true value. – slacker Apr 16 '10 at 18:13
  • 1
    @indiv: there are certainly many series that converge faster. But this one is simple and may be more appropriate for an idle programming exercise, which I assumed was the purpose of the question. @user146780: if I've misinterpreted your meaning and you intend to use this in production code. Do not do this. Grab as many digits as you need off a published version on the net and save that. – Alan Apr 16 '10 at 18:46
  • 8
    @Alan: OK, but the question clearly says he's trying to write a function that can compute PI to X places... Anyway, I implemented this taylor series and after 1 billion iterations you have "3.14159265". After 3 billion iterations you have the next digit. The digit after that comes after 99 billion iterations. 99 billion. – indiv Apr 16 '10 at 22:59
  • 2
    Yes, if you want n decimal digits of precision, you'll need something on the order of 10^n iterations. I'm not disputing that it converges slowly. The OP seems to be interested in a learning exercise, not something of practical use. – Alan Apr 17 '10 at 04:30
  • This requires BigNum's and `O(n)` space o find the n'th place. There are `O(1)` space algorithms for the n'th binary place of π, but I'm not sure if an algorithm like that exists for the n'th decimal place. – R.. GitHub STOP HELPING ICE Feb 08 '11 at 06:56
  • "Google it if you want the answer" I _did_ and now I'm _here_. – ryvantage Feb 05 '20 at 19:17
7

Try "Computation of the n'th digit of pi in any base in O(n^2)". It's probably the fastest known algorithm that doesn't require arbitrary (read huge) precision floats, and can give you the result directly in base 10 (or any other).

the Tin Man
  • 158,662
  • 42
  • 215
  • 303
slacker
  • 2,142
  • 11
  • 10
6

As an alternative to JeffH's method of storing every variation, you can just store the maximum number of digits and cut off what you don't need:

#include <string>
#include <iostream>
using std::cout; using std::endl; using std::string;

// The first 99 decimal digits taken from:
// http://www.geom.uiuc.edu/~huberty/math5337/groupe/digits.html
// Add more as needed.
const string pi =
  "1415926535"
  "8979323846"
  "2643383279"
  "5028841971"
  "6939937510"
  "5820974944"
  "5923078164"
  "0628620899"
  "8628034825"
  "342117067";

// A function in C++ that returns pi to X places
string CalcPi(const size_t decimalDigitsCount) 
{
  string returnValue = "3";
  if (decimalDigitsCount > 0)
  {
    returnValue += "." + pi.substr(0, decimalDigitsCount);
  }
  return returnValue;
} 

int main()
{
  // Loop through all the values of "pi at x digits" that we have. 
  for (size_t i = 0; i <= pi.size(); ++i) 
  {
    cout << "pi(" << i << "): " << CalcPi(i) << endl;
  } 
}

http://codepad.org/6mqDa1zj

Bill
  • 14,257
  • 4
  • 43
  • 55
  • 7
    Given that pi is not going to change and that 43 digits is enough precision to calculate the circumference of the universe to a tolerance of the width of *1* proton, this is a pretty reasonable. Unfortunately, the question is about calculating the X'th digit and does not necessarily mean you have to get the digits before digit X and it wouldn't really be a solution here as X could be *anything*! – Neil Trodden Apr 18 '10 at 19:35
  • *"...of the universe"* should read *"...of the **observable** universe"*. – trincot Feb 16 '22 at 09:30
6

I believe the algorithm you're looking for is what's known as a "Spigot Algorithm." One particular kind is the BBP (Bailey-Borwein-Plouffe) formula.

I believe that's what you're looking for.

Mike Bailey
  • 12,479
  • 14
  • 66
  • 123
4

I'd start with the formula

pi = 16 arctan (1/5) - 4 arctan (1/239)

Google will easily find a proof for this formula that normal human beings can understand, and a formula to calculate the arc tangent function. This will allow you to calculate a few thousand decimal digits of pi quite easily and quickly.

gnasher729
  • 51,477
  • 5
  • 75
  • 98
3

Are you willing to look up values instead of computing them?

Since you didn't explicitly specify that your function has to calculate values, here's a possible solution if you are willing to have an upper limit on the number of digits it can "calculate":

// Initialize pis as far out as you want. 
// There are lots of places you can look up pi out to a specific # of digits.
double pis[] = {3.0, 3.1, 3.14, 3.141, 3.1416}; 

/* 
 * A function that returns pi out to a number of digits (up to a point)
 */
double CalcPi(int x)
{
    // NOTE: Should add range checking here. For now, do not access past end of pis[]
    return pis[x]; 
}

int main()
{
    // Loop through all the values of "pi at x digits" that we have.
    for (int ii=0; ii<(int)sizeof(pis)/sizeof(double); ii++)
    {
        double piAtXdigits = CalcPi(ii);
    }
}

Writing CalcPi() this way (if it meets your needs) has a side benefit of being equally screaming fast for any value of X within your upper limit.

JeffH
  • 10,254
  • 2
  • 27
  • 48
  • 1
    This solution could be coupled to a "computing solution": the array could be declared in a .hpp and defined (i.e. filled) by a metaprogram generating the corresponding .cpp file. The metaprogram would be parameterized by the maximum number of digits needed, and would compute the values to set them into the array. – Luc Touraille Apr 16 '10 at 21:37
3

"π IN THE MANDELBROT SET" explores the curious relationship between a sequence of points on the complex plane and how computing their "Mandelbrot number" (for lack a better term ... the number of iterations required to determine that the points in the sequence are not members of the Mandelbrot set) relates to PI.

Practical? Probably not.

Unexpected and interesting? I think so.

the Tin Man
  • 158,662
  • 42
  • 215
  • 303
andand
  • 17,134
  • 11
  • 53
  • 79
2

My two cents... This might not be the fastest, but I think it's quite easy to understand. I came up with it myself during a math lecture, and I haven't really seen it anywhere else in literature. Either I'm a genius, really stupid, or don't really pay attention to reading books about math, or all of the above... :)

Anyway... Start with the unit circle. We know that x^2+y^2=1, so y=sqrt(1-x^2). We also know that the area of the unit circle is PI. If we now take the integral of the function sqrt(1-x^2) in the range 0 to 1, we will get a quarter of PI. So multiply it by 4 to get PI:

PI formula

If we would try to solve this analytically, I'm sure we would just get PI back. But it's quite easy to write a program to solve it numerically. The following one is in C:

#include <math.h>
#include <stdio.h>

void main(void) {
    double interval=0.0000001,area=0,x,y;

    for (x=0; x<1; x+=interval)
        area+=4*interval*sqrt(1-x*x);

    printf("pi ~ %.20f\n",area);
}

Running it with the above setting for interval, we get:

pi ~ 3.14159285415672595576

So 10,000,000 iterations give 6 correct decimals. Not the most efficient, but it's my baby... :)

Mikael Lindqvist
  • 775
  • 5
  • 21
  • 1
    This is based on the assumption, that floating point numbers behaved like rational numbers. That [assumption is wrong](https://stackoverflow.com/q/588004/1889329). Depending on the input, this implementation produces **wildly** differing results. The accuracy of the result remains unknown. – IInspectable Dec 21 '19 at 10:08
0
pi = function () {
    let pi = 3;
    let a = 3;
    let even = false;
    let turn;

    while (a <= 90000) {
        turn = (4/((Math.pow(a, 3)) - (a)));

        if(even){
            turn = turn*-1;
            even = false;
        } else {
            even = true;
        }
        pi = pi + turn;
        a = a + 2;
    }
    return pi;
};
T.Arnold
  • 1
  • 1
  • 1
    @t-arnold you've implemented function, but it would be good to have some explanation also. – Sergii Nov 23 '17 at 15:39
0

I was able to calculate PI to somewhat close to actual pi. Here is the c++ implementation of it.

#include <iostream>
#include <iomanip>
#include <cmath>

using namespace std;

long double calPI(long iterations = 1000)
{
    long double pi = 0.0, factor = 1;
    long i;
    for (i = 2; i < iterations; i += 2, factor *= -1)
    {
        pi += factor / (i - 1.0);
    }
    return 4 * pi;
}
// 3.14159265358979323846264338327950288419716939937510          -> Actual (50 digits)
// 3.141592653589793115997963468544185161590576171875            -> From acos
// 3.14159265452113118342880593303334535448811948299407958984375 -> Calculated
int main()
{
    int digits;
    long double PI;
    cout << "Enter how many digits of precision you want to have : ";
    cin >> digits;
    PI = calPI(2147453647); // By far the maximum precision I was able to reach
    cout << "The value of pi upto " << digits << " digits : " << setprecision(digits) << PI << endl;
    cout << "Actual value of pi from math.h : " << 2 * acos(0.0) << endl;
    return 0;
}

There is actually a very nice explination of how the series I used was derives here and I highly recommend you watch that.

-1
import math
def pi(x):
    for i in range(1,x):
        print( (360.0*math.tan(math.radians(1/(2*i))))/(1/i))

It's done like by getting the smallest possible, then I use that angle to calculate the no. of sides.

The length of the sides is calculated using trigonometry then... you can also replace the math.tan with math.sin.

MLavoie
  • 9,671
  • 41
  • 36
  • 56
xavier
  • 1