7

I have always wanted to find an algorithm that did this. I do not care how slow it is, just as long as it can return the nth digit of Pi:

ex:

size_t piAt(long long int n)
{
}

Preferably, not using an infinite series.

If anyone has a function or class that does this, in C or C++ I'd really be interested in seeing it.

Thanks

jmasterx
  • 52,639
  • 96
  • 311
  • 557
  • 5
    This seems like an exact duplicate of http://stackoverflow.com/questions/2654749/how-is-pi-calculated (your own question from one year ago). Is there some reason you asked again as a new question? – Mu Mind May 06 '11 at 01:15
  • @ Mu Mind that was the formula, but now I'm asking for the implementation. – jmasterx May 06 '11 at 01:16
  • @jmasterx see [Baking-Pi Challenge - Understanding & Improving](http://stackoverflow.com/a/22295383/2521214) especially bullet **#3** in my answer there... – Spektre Mar 15 '16 at 07:02
  • Wouldn't you want this to return an `int`, or an `unsigned int`, rather than a `size_t`? – Tom Karzes Mar 19 '16 at 01:01

3 Answers3

12

Here is a solution of Simon Plouffe coded by Fabrice Bellard:

   /*
     * Computation of the n'th decimal digit of \pi with very little memory.
     * Written by Fabrice Bellard on January 8, 1997.
     * 
     * We use a slightly modified version of the method described by Simon
     * Plouffe in "On the Computation of the n'th decimal digit of various
     * transcendental numbers" (November 1996). We have modified the algorithm
     * to get a running time of O(n^2) instead of O(n^3log(n)^3).
     * 
     * This program uses mostly integer arithmetic. It may be slow on some
     * hardwares where integer multiplications and divisons must be done
     * by software. We have supposed that 'int' has a size of 32 bits. If
     * your compiler supports 'long long' integers of 64 bits, you may use
     * the integer version of 'mul_mod' (see HAS_LONG_LONG).  
     */

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

/* uncomment the following line to use 'long long' integers */
/* #define HAS_LONG_LONG */

#ifdef HAS_LONG_LONG
#define mul_mod(a,b,m) (( (long long) (a) * (long long) (b) ) % (m))
#else
#define mul_mod(a,b,m) fmod( (double) a * (double) b, m)
#endif

/* return the inverse of x mod y */
int inv_mod(int x, int y)
{
    int q, u, v, a, c, t;

    u = x;
    v = y;
    c = 1;
    a = 0;
    do {
    q = v / u;

    t = c;
    c = a - q * c;
    a = t;

    t = u;
    u = v - q * u;
    v = t;
    } while (u != 0);
    a = a % y;
    if (a < 0)
    a = y + a;
    return a;
}

/* return (a^b) mod m */
int pow_mod(int a, int b, int m)
{
    int r, aa;

    r = 1;
    aa = a;
    while (1) {
    if (b & 1)
        r = mul_mod(r, aa, m);
    b = b >> 1;
    if (b == 0)
        break;
    aa = mul_mod(aa, aa, m);
    }
    return r;
}

/* return true if n is prime */
int is_prime(int n)
{
    int r, i;
    if ((n % 2) == 0)
    return 0;

    r = (int) (sqrt(n));
    for (i = 3; i <= r; i += 2)
    if ((n % i) == 0)
        return 0;
    return 1;
}

/* return the prime number immediatly after n */
int next_prime(int n)
{
    do {
    n++;
    } while (!is_prime(n));
    return n;
}

int main(int argc, char *argv[])
{
    int av, a, vmax, N, n, num, den, k, kq, kq2, t, v, s, i;
    double sum;

    if (argc < 2 || (n = atoi(argv[1])) <= 0) {
    printf("This program computes the n'th decimal digit of \\pi\n"
           "usage: pi n , where n is the digit you want\n");
    exit(1);
    }

    N = (int) ((n + 20) * log(10) / log(2));

    sum = 0;

    for (a = 3; a <= (2 * N); a = next_prime(a)) {

    vmax = (int) (log(2 * N) / log(a));
    av = 1;
    for (i = 0; i < vmax; i++)
        av = av * a;

    s = 0;
    num = 1;
    den = 1;
    v = 0;
    kq = 1;
    kq2 = 1;

    for (k = 1; k <= N; k++) {

        t = k;
        if (kq >= a) {
        do {
            t = t / a;
            v--;
        } while ((t % a) == 0);
        kq = 0;
        }
        kq++;
        num = mul_mod(num, t, av);

        t = (2 * k - 1);
        if (kq2 >= a) {
        if (kq2 == a) {
            do {
            t = t / a;
            v++;
            } while ((t % a) == 0);
        }
        kq2 -= a;
        }
        den = mul_mod(den, t, av);
        kq2 += 2;

        if (v > 0) {
        t = inv_mod(den, av);
        t = mul_mod(t, num, av);
        t = mul_mod(t, k, av);
        for (i = v; i < vmax; i++)
            t = mul_mod(t, a, av);
        s += t;
        if (s >= av)
            s -= av;
        }

    }

    t = pow_mod(10, n - 1, av);
    s = mul_mod(s, t, av);
    sum = fmod(sum + (double) s / (double) av, 1.0);
    }
    printf("Decimal digits of pi at position %d: %09d\n", n,
       (int) (sum * 1e9));
    return 0;
}

And it works:

C:\tcc>tcc -I libtcc libtcc/libtcc.def -run examples/pi.c 1
Decimal digits of pi at position 1: 141592653

C:\tcc>tcc -I libtcc libtcc/libtcc.def -run examples/pi.c 1000
Decimal digits of pi at position 1000: 938095257

http://bellard.org/pi/pi_n2/pi_n2.html

Lehs
  • 812
  • 6
  • 18
  • While this link may answer the question, it is better to include the essential parts of the answer here and provide the link for reference. Link-only answers can become invalid if the linked page changes. – AbcAeffchen Jan 18 '15 at 10:31
  • This does not provide an answer to the question. To critique or request clarification from an author, leave a comment below their post. – dario Jan 18 '15 at 10:45
  • @AbcAeffchen: I'm working on it, but my interpretation of the paper doesn't work in my program yet. – Lehs Jan 18 '15 at 10:48
  • @king.code: Milo is asking for a function that gives the nth decimal of pi. The paper contains an algorithm that do exactly that, which would be a first step to code a c-program. – Lehs Jan 18 '15 at 10:50
  • @king.code: well, as I wrote: I'm working on an algorithm and will post it as soon as it works. – Lehs Jan 18 '15 at 10:52
  • @Lehs so you'll post when you are done. Have a look at [this](http://stackoverflow.com/help/how-to-answer). – dario Jan 18 '15 at 10:54
  • 1
    It works! Nice answer. I'd like to measure how close the implementation is to O(n²). – Niklas Rosencrantz Mar 14 '16 at 19:07
10

This remarkable solution shows how to compute the Nth digit of π in O(N) time and O(log·N) space, and to do so without having to compute all the digits leading up to it.

Oh, and it’s in hex.

If you don’t want to do that, you can do this from the shell easily enough:

% perl -Mbignum=bpi -wle 'print bpi(20)'
3.1415926535897932385

% perl -Mbignum=bpi -wle 'print bpi(50)'
3.1415926535897932384626433832795028841971693993751

% perl -Mbignum=bpi -wle 'print bpi(200)'
3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679821480865132823066470938446095505822317253594081284811174502841027019385211055596446229489549303820

% perl -Mbignum=bpi -wle 'print bpi(1000)'
3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117067982148086513282306647093844609550582231725359408128481117450284102701938521105559644622948954930381964428810975665933446128475648233786783165271201909145648566923460348610454326648213393607260249141273724587006606315588174881520920962829254091715364367892590360011330530548820466521384146951941511609433057270365759591953092186117381932611793105118548074462379962749567351885752724891227938183011949129833673362440656643086021394946395224737190702179860943702770539217176293176752384674818467669405132000568127145263560827785771342757789609173637178721468440901224953430146549585371050792279689258923542019956112129021960864034418159813629774771309960518707211349999998372978049951059731732816096318595024459455346908302642522308253344685035261931188171010003137838752886587533208381420617177669147303598253490428755468731159562863882353787593751957781857780532171226806613001927876611195909216420199
tchrist
  • 78,834
  • 30
  • 123
  • 180
  • This is perfect, but I'm looking for an implementation since I do not understand the formula, specifically for k = 0 to infinity... – jmasterx May 06 '11 at 01:19
  • 7
    @Milo: do you have a specific qyestion or problem with how you're trying to implement it? This isn't writemeaprogram.com – Wooble May 06 '11 at 01:31
  • Could you write out, how you would use the formula where n is for example 5 ? I'm just not sure how to use the formula. – jmasterx May 06 '11 at 01:35
  • 4
    @Milo: if you don't understand the formula and can't do the programming, then you're not learning anything from this and presumably have a practical need: perhaps it can be satisfied by reading the value of pi from a file (you can download such from the 'net - e.g. http://www.piday.org/million.php), and indexing in at the position you're interested in? Save you a lot of compute time.... ;-) – Tony Delroy May 06 '11 at 01:37
  • No, I have no practical use for it, I'd use a static lookup table for that, I'm just interested in a program that can compute the nth digit of pi. – jmasterx May 06 '11 at 01:40
  • @Milo: Answered updated. The Perl `bignum` module has a `bpi(N)` function that returns π to N digits of accuracy. – tchrist May 06 '11 at 01:48
  • 4
    Calculating the Nth digit in base 16 is very different from calculating the Nth digit in base 10. Going from one to the other has nontrivial big-O in both time and space! – R.. GitHub STOP HELPING ICE May 06 '11 at 03:04
  • @TonyK: After giving it some extra thought I deleted my comment. – datenwolf Jan 18 '15 at 14:07
  • 1
    This answer has nothing to do with OP's question; the link describes how to find the Nth base-16 digit whereas the question implies base 10. – M.M Aug 22 '16 at 23:50
  • 1
    Everyone who find this page are here for ONE REASON: they have a practical need. – Mr. Developerdude Mar 24 '17 at 20:23
  • 1
    "Oh, and it’s in hex." smh – Viliami May 22 '17 at 21:28
0

Several of the solutions including this one actually print several digits starting with the nth digit.

There is a fine ( and strikingly faster than previous answers) solution at http://numbers.computation.free.fr/Constants/Algorithms/pidec.cpp

The code only needs modification of "typedef int64 ModInt;" line to "typedef int64_t ModInt;"

gcc pidec.cpp && time echo 20000 | ./a.out
Pidec, direct computation of decimal digits of pi at a given position n.
(http://numbers.computation.free.fr/Constants/constants.html for more details)
Enter n : Parameters : M=122, N=7094, M*N+M=872562
Series time : 0.17
Digits of pi after n-th decimal digit : 203856539
Total time: 0.68

real    0m0.691s
user    0m0.678s
sys 0m0.006s

Compilation finished at Wed Feb  3 13:34:48

This on a "early 2015" macbook pro.

brucer42
  • 1
  • 1