Perl: the Markov chain saw PerlMonks

### Re: Computing pi to multiple precision

by moritz (Cardinal)
 on Sep 09, 2012 at 14:45 UTC ( #992590=note: print w/replies, xml ) Need Help??

in reply to Computing pi to multiple precision

Ever since I've read about them, I've been fascinated by spigot algorithms for producing digits of pi.

The basic idea for those algorithms is that most "interesting" transcendental numbers (like pi, e, ln(2)) have a pretty simple representation if the base is allowed (in a regular pattern) for each digit. Then the task of computing the first \$N first digits is just that of a base conversion. And the fascinating part is that you can work with integers only-

To stay a bit on topic, I've ported this C implementation of a spigot algorithm for pi to Perl 6:

```sub pi-spigot(Int \$digits) {
my \$len = 1 + floor 10 * \$digits / 3;
my @a = 2 xx \$len;
my Int \$nines    = 0;
my Int \$predigit = 0;
join '', gather for 1 .. (\$digits + 1) -> \$j {
my Int \$q = 0;
loop (my int \$i = \$len; \$i > 0; \$i = \$i - 1) {
my int \$x = 10 * @a[\$i - 1] + \$q * \$i;
@a[\$i - 1] = \$x % ( 2 * \$i - 1);
\$q = \$x div (2 * \$i - 1);
}

@a[0] = \$q % 10;
\$q div= 10;
if \$q == 9 {
++\$nines;
}
elsif \$q == 10 {
take \$predigit + 1, 0 xx \$nines;
\$nines    = 0;
\$predigit = 0;
}
else {
take \$predigit;
\$predigit = \$q;
take 9 xx \$nines;
\$nines = 0;
}
}
}

multi MAIN(\$n = 100) {
say pi-spigot(\$n.Int);
}

multi MAIN('test') {
use Test;
plan 1;
is pi-spigot(100),
'03141592653589793238462643383279502884197169399375105820974944
+59230781640628620899862803482534211706',
'it works';
}

Since Rakudo is still pretty slow for this kind of stuff, I've traded a bit of readabilty for speed by using a native int in the inner loop, which means that Rakudo can inline most operators, but means I have to write \$i = \$i - 1 instead of \$i-- (because native ints are value types, and you cannot (yet?) pass them as writable values to routines, so the -- operator cannot work on them).

Replies are listed 'Best First'.
Re^2: Computing pi to multiple precision
by ambrus (Abbot) on Sep 09, 2012 at 16:30 UTC

But wait, if you print the value all at once, then why do you need the complicated incremental radix conversion routine? Why not just generate the whole binary representation at once, then convert it to decimal all at once, using the built in bigfloat or bigint operations? (Sorry, I won't write that in code now.)

The point is exactly that you don't need a full bigint or bigfloat implementation to compute a few hundred digits of pi.

Re^2: Computing pi to multiple precision
by Athanasius (Chancellor) on Sep 10, 2012 at 16:36 UTC

I found a nice Perl 5 implementation of a spigot algorithm to generate pi at http://rosettacode.org/wiki/Pi#Perl. With a bit of tweaking, I was able to convert this code into a true spigot: a function which returns a further sequence of digits on each successive call:

• The output is in decimal.
• The output can be displayed progressively, so that, for a large number of digits, the user can ‘see’ that progress is being made.
• With use of the GMP library, performance is surprisingly fast (10,000 digits in under a minute).
• Flexibility: the caller is free to display or otherwise use the data returned as required.

Let me emphasize, the code is not mine, I have only massaged it into a (hopefully) more useful form. Perhaps it will prove interesting or helpful to others exploring this topic.

Athanasius <°(((><contra mundum

Re^2: Computing pi to multiple precision
by ambrus (Abbot) on Sep 09, 2012 at 16:00 UTC
Re^2: Computing pi to multiple precision
by martin (Friar) on Sep 12, 2012 at 13:21 UTC

As the author points out, representation change algorithms like these are showcase examples for lazy evaluation. This in turn makes Perl 6 a very good language to implement them, besides Haskell.

With the techniques explained in the article you can replace the large fixed-size array @a for the state by two FatRats or four Integers and actually return an infinite series of decimal digits (limited only by memory resources as the state numbers grow).

These algorithms are not particularly fast, but not half bad either. Perfect, if you want to incrementally increase precision as you need it. In fact, they could be used in a framework for arbitrarily precise real arithmetic. I would love Perl 6 to support high precision math beyond rational arithmetic.

Create A New User
Node Status?
node history
Node Type: note [id://992590]
help
Chatterbox?
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others examining the Monastery: (3)
As of 2018-06-18 00:19 GMT
Sections?
Information?
Find Nodes?
Leftovers?
Voting Booth?
Should cpanminus be part of the standard Perl release?

Results (107 votes). Check out past polls.

Notices?