Trivial -- but magical:
BBP <- function(n = 13) {
sum(sapply(seq_len(n), function(k) {
((sample.int(8*k+1, 1) <= 4) -
(sample.int(8*k+4, 1) <= 2) -
(sample.int(8*k+5, 1) <= 1) -
(sample.int(8*k+6, 1) <= 1)) / 16^k
})) + (4 - 2/4 - 1/5 - 1/6)
}
As you can see in this R
code, only rational arithmetic operations (comparison, subtraction, division, and addition) are performed on the results of a small number of draws of integral values using sample.int
. By default, only $13*4=52$ draws are made (of values never greater than $110$) -- but the expected value of the result is $\pi$ to full double-precision!
Here is a sample run of $10,000$ iterations (requiring one second of time):
x <- replicate(1e4, BBP())
mu <- mean(x)
se <- sd(x) / sqrt(length(x))
signif(c(Estimate=mu, SE=se, Z=(mu-pi)/se), 4)
Its output is
Estimate SE Z
3.1430000 0.0004514 2.0870000
In other words, this (random) estimate of $\pi$ is $3.143\pm 0.00045$ and the smallish Z-value of $2.08$ indicates this doesn't deviate significantly from the true value of $\pi.$
This is trivial because, as I hope the code makes obvious, calculations like sample.int(b,1) <= a
(when the integer a
does not exceed b
) are just stupid ways to estimate the rational fractions a/b
. Thus, this code estimates the Bailey Borwein Plouffe formula
$$\pi = \sum_{k=0}^\infty \frac{1}{16^k}\left(\frac{4}{8k+1}-\frac{2}{8k+4}-\frac{1}{8k+5}-\frac{1}{8k+6}\right)$$
by expressing the $k=0$ term explicitly and sampling all subsequent terms through $k=13.$ Since each term in the formula introduces $4$ additional bits in the binary expansion of $\pi,$ terminating the sampling at this point gives $4*(13)=52$ bits after the binary point, which is slightly more than the maximal $52$ total bits of precision available in the IEEE double precision floats used by R
.
Although we could work out the variance analytically, the previous example already gives us a good estimate of it, because the standard error was only $0.0045,$ associated with a variance of $0.002$ per iteration.
var(x)
[1] 0.002037781
Thus, if you would like to use BBP
to estimate $\pi$ to within a standard error of $\sigma,$ you will need approximately $0.002/\sigma^2$ iterations. For example, estimating $\pi$ to six decimal places in this manner will require around two billion iterations (about three days of computation).
One way to reduce the variance (greatly) would be to compute a few more of the initial terms in the BBP sum once and for all, using Monte Carlo simulation only to estimate the least significant bits of the result :-).