Calculate Pi

There is not yet a FixDecimal type module in Raku, and using FatRat all along would be too slow and would be coerced to Num when computing the square root anyway, so we'll use a custom definition of the square root for Int and FatRat, with a limitation to the number of decimals. We'll show all the intermediate results.

The trick to compute the square root of a rational n d {\displaystyle n \over d} {\displaystyle n\over d} up to a certain amount of decimals N is to write:

n d = n 10 2 N / d d 10 2 N / d = n 10 2 N / d 10 N {\displaystyle {\sqrt {\frac {n}{d}}}={\sqrt {\frac {n10^{2N}/d}{d10^{2N}/d}}}={\frac {\sqrt {n10^{2N}/d}}{10^{N}}}} {\displaystyle \sqrt{\frac{n}{d}} = \sqrt{
\frac{n 10^{2N} / d}{d 10^{2N} / d}
} = \frac{\sqrt{n 10^{2N} / d}}{10^N}}

so that what we need is one square root of a big number that we'll truncate to its integer part. We'll use the method described in Integer rootsarrow-up-right to compute the square root of this big integer.

Notice that we don't get the exact number of decimals required : the last two decimals or so can be wrong. This is because we don't need a n {\displaystyle a_{n}} {\displaystyle a\_n}, but rather a n 2 {\displaystyle a_{n}^{2}} {\displaystyle a\_n^2}. Elevating to the square makes us lose a bit of precision. It could be compensated by choosing a slightly higher value of N (in a way that could be precisely calculated), but that would probably be overkill.

constant number-of-decimals = 100;

multi sqrt(Int $n) {
  (10**($n.chars div 2), { ($_ + $n div $_) div 2 } ... * == *).tail
}

multi sqrt(FatRat $r --> FatRat) {
  return FatRat.new:
    sqrt($r.numerator * 10**(number-of-decimals*2) div $r.denominator),
    10**number-of-decimals;
}

my FatRat ($a, $n) = 1.FatRat xx 2;
my FatRat $g = sqrt(1/2.FatRat);
my $z = .25;

for ^10 {
  given [ ($a + $g)/2, sqrt($a * $g) ] {
    $z -= (.[0] - $a)**2 * $n;
    $n += $n;
    ($a, $g) = @$_;
    say ($a ** 2 / $z).substr: 0, 2 + number-of-decimals;
  }
}

Output:

Last updated

Was this helpful?