Monday, March 14, 2022

"Pi" day: pi digits & code

Pi - Wikipedia  π

fast "PI" calculation is now possible thanks to (relatively) new algorithm
and languages as Python and now JavaScript that support "unlimited" digits numbers

Pi - Rosetta Code, in many programming languages

cs.ox.ac.uk/people/jeremy.gibbons/publications/spigot.pdf

Unbounded Spigot Algorithms for the Digits of Pi Jeremy Gibbons

PY: pi digits: 10000 time:  11.72525 sec JS: PiGen digits: 10000 time: 26.08004309999943 sec
C#: Pi digits: 10000 time: 15.902 sec Go: GenPiA digits: 10000 time: 6.1173453s

BigInt - JavaScript | MDN

BigIntBigInt is a special numeric type that provides support for integers of arbitrary length.

BigInt | Can I use... Support tables for HTML5, CSS3, etc

BigInt numbers in JavaScript have "n" suffix when assigned

JavaScript

function* genPi() {
  var [q, r, t, k, n, l, nn, nr] = [1n, 0n, 1n, 1n, 3n, 3n, 0n, 0n]
  while (true) {
    if (4n * q + r - t < n * t) {
      yield n
      nr = 10n * (r - n * t)
      n = (10n * (3n * q + r)) / t - 10n * n
      q *= 10n
      r = nr
    } else {
      nr = (2n * q + r) * l
      nn = (q * (7n * k) + 2n + (r * l)) / (t * l)
      q *= k
      t *= l
      l += 2n
      k += 1n
      n = nn
      r = nr
    }
  }
}

const pi = genPi();
for (var i = 0; i < 1000; i++) {
  console.log(pi.next().value.toString());
}

Pi - Rosetta Code: Python

def gen_pi():
    q, r, t, k, n, l = 1, 0, 1, 1, 3, 3
    while True:
        if 4*q+r-t < n*t:
            yield n
            nr = 10*(r-n*t)
            n = ((10*(3*q+r))//t)-10*n
            q *= 10
            r = nr
        else:
            nr = (2*q+r)*l
            nn = (q*(7*k)+2+(r*l))//(t*l)
            q *= k
            t *= l
            l += 2
            k += 1
            n = nn
            r = nr

count = 0
for d in gen_pi():
    sys.stdout.write(str(d))
    count += 1
    if count >= 1000:
        break
3141592653589793238462643383279502884197
1693993751058209749445923078164062862089
9862803482534211706798214808651328230664
7093844609550582231725359408128481117450
2841027019385211055596446229489549303819
6442881097566593344612847564823378678316
5271201909145648566923460348610454326648
2133936072602491412737245870066063155881
7488152092096282925409171536436789259036
0011330530548820466521384146951941511609
4330572703657595919530921861173819326117
...

C# (dotnet)

  public static IEnumerable<BigInteger> GenPiDigits()
  {
    BigInteger b1 = BigInteger.One, b2 = new BigInteger(2), b3 = new BigInteger(3),
      b4 = new BigInteger(4), b7 = new BigInteger(7), b10 = new BigInteger(10),
      k = b1, l = b3, n = b3, q = b1, r = BigInteger.Zero, t = b1, nn, nr;
    while (true)
    {
      if ((b4 * q + r - t).CompareTo(n * t) == -1)
      {
        yield return n;
        nr = b10 * (r - (n * t));
        n = b10 * (b3 * q + r) / t - (b10 * n);
        q *= b10;
        r = nr;
      }
      else
      {
        nr = (b2 * q + r) * l;
        nn = (q * (b7 * k) + b2 + r * l) / (t * l);
        q *= k;
        t *= l;
        l += b2;
        k += b1;
        n = nn;
        r = nr;
      }
    }
  }

 int i = 0;
  foreach (var n in Algorithms.GenPiDigits())
  {
Console.Write(n.ToString());
    if (i++ > 1000) break;
  }

GoLang

import (
  "math/big" // https://pkg.go.dev/math/big#Int
)

// returns an array (slice) of "max" digits of pi
// the BitInt lib has specific syntax that makes code more complex; it is fast though :)
func GenPiA(max int) []int {
  _1, _2, _3, _4, _7, _10 := big.NewInt(1), big.NewInt(2), big.NewInt(3), big.NewInt(4), big.NewInt(7), big.NewInt(10)
  q, r, t, k, n, l, nn, nr := big.NewInt(1), big.NewInt(0), big.NewInt(1), big.NewInt(1), big.NewInt(3), big.NewInt(3), big.NewInt(0), big.NewInt(0)
  _x, _y := new(big.Int), new(big.Int)
  i := 0
  var digits []int = make([]int, max)
  for {
    // if (4n * q + r - t < n * t) {
    if _x.Mul(_4, q).Add(_x, r).Sub(_x, t).Cmp(_y.Mul(n, t)) == -1 {
      digits[i] = int(n.Int64())
      i += 1
      if i >= max {
        return digits
      }
      // nr = 10n * (r - n * t)
      nr.Mul(_10, _x.Sub(r, _y.Mul(n, t)))
      // n = (10n * (3n * q + r)) / t - 10n * n
      n.Mul(_3, q).Add(n, r).Mul(n, _10).Div(n, t).Sub(n, _y.Mul(_10, n))
      q.Mul(q, _10) // q *= 10n
      r.Set(nr)     // r = nr
    } else {
      // nr = (2n * q + r) * l
      nr.Mul(_x.Add(_y.Mul(_2, q), r), l)
      // nn = (q * (7n * k) + 2n + (r * l)) / (t * l)
      nn.Mul(_7, k).Mul(nn, q).Add(nn, _2).Add(nn, _x.Mul(r, l)).Div(nn, _y.Mul(t, l))
      q.Mul(q, k)  // q *= k
      t.Mul(t, l)  // t *= l
      l.Add(l, _2) // l += 2n
      k.Add(k, _1) // k += 1n
      n.Set(nn)    // n = nn
      r.Set(nr)    // r = nr
    }
  }
}


Pi - Rosetta Code PicoLisp

picolisp/picolisp: PicoLisp is an open source Lisp dialect. It runs on Linux and other POSIX-compliant systems. Its most prominent features are simplicity and minimalism. @GitHub

Pi - Rosetta Code: C

Pi - Rosetta Code: Go




This algorithm is based on an unproven conjecture but successfully produces at least the first 1 million digits. Read more about it here: https://www.gavalas.dev/blog/spigot-algorithms-for-pi-in-python/

Python: less code, more time

def gospers_pi_unproven():
    q, r, t, i = 1, 180, 60, 2
    while True:
        u, y = 3*(3*i+1)*(3*i+2), (q*(27*i-12)+5*r)//(5*t)
        yield y
        q, r, t, i = 10*q*i*(2*i-1), 10*u*(q*(5*i-2)+r-y*t), t*u, i+1

JavaScript

// Calculate digits of π, yields digits one by one
function* GenPi2() {
  let q = 1n, r = 180n, t = 60n
  for (let i = 2n; ; i += 1n) {
    let y = (q * (27n * i - 12n) + 5n * r) / (5n * t)
    let u = 3n * (3n * i + 1n) * (3n * i + 2n)
    r = 10n * u * (q * (5n * i - 2n) + r - y * t)
    q = 10n * q * i * (2n * i - 1n)
    t = t * u
    yield Number(y)
  }
}

GoLang: more code, less execution time :) Was not easy to make it work... 

// returns an array (slice) of "max" digits of pi
// the BitInt lib has specific syntax that makes code much more complex; it is fast though :)
func GenPi2A(max int) []int {
  _1, _2, _3, _5, _10, _12, _27 :=
    big.NewInt(1), big.NewInt(2), big.NewInt(3), big.NewInt(5), big.NewInt(10), big.NewInt(12), big.NewInt(27)
  // q = 1, r = 180, t = 60, i = 2
  q, r, t, i := big.NewInt(1), big.NewInt(180), big.NewInt(60), big.NewInt(2)
  y, u, x := new(big.Int), new(big.Int), new(big.Int)
  var digits []int = make([]int, max)
  for count := 0; count < max; count++ {
    // y = (q * (27 * i - 12) + 5 * r) / (5 * t) = ((27 * i - 12) * q + (5 * r)) / (5 * t)
    y.Mul(_27, i).Sub(y, _12).Mul(y, q).Add(y, x.Mul(_5, r)).Div(y, x.Mul(_5, t))
    // u = 3 * (3 * i + 1) * (3 * i + 2) = ((3 * i) + 1) * ((3 * i) + 2) * 3
    // u.Mul(_3, i).Add(u, _1).Mul(u, _3).Mul(u, x.Mul(_3, i).Add(x, _2)) // 6 calls
    u.Add(x.Mul(_3, i), _1).Mul(u, x.Add(x, _2)).Mul(u, _3) // 5 calls, better, faster
    // r = 10 * u * (q * (5 * i - 2) + r - y * t) = (r - (y * t) + (5 * i - 2) * q) * 10 * u
    r.Sub(r, x.Mul(y, t)).Add(r, x.Mul(_5, i).Sub(x, _2).Mul(x, q)).Mul(r, _10).Mul(r, u)
    // q = 10 * q * i * (2 * i - 1)
    q.Mul(_10, q).Mul(q, i).Mul(q, x.Mul(_2, i).Sub(x, _1))
    // t = t * u
    t.Mul(t, u)
    // digits[count] = Number(y)
    digits[count] = int(y.Int64())
    // i += 1
    i.Add(i, _1)
  }
  return digits
}


there is "official" competition of programming languages and algorithms, here:

pidigits (Benchmarks Game)

The Computer Language
22.03 Benchmarks Game



digits of Pi are also available online

including first 1000 digits of Pi


a very large number of digits of Pi is calculated by Google (as world record) and available as API

Google: serving the Pi (world record)




REST API to fetch 100 digits of Pi from the specified starting point 
(max 1000 digits per request), example:


more info:



For JPL's highest accuracy calculations, which are for interplanetary navigation, we use 3.141592653589793 (15 digits)

The most distant spacecraft from Earth is Voyager 1. It is about 12.5 billion miles away.
... calculated circumference of the 25 billion mile diameter circle would be wrong by 1.5 inches.

No comments: