Article 5PBJQ Functions in bc

Functions in bc

by
John
from John D. Cook on (#5PBJQ)

The previous post discussed how you would plan an attempt to set a record in computing (3), also known as Apery's constant. Specifically that post looked at how to choose your algorithm and how to anticipate the number of terms to use.

Now suppose you wanted to actually do the calculation. This post will carry out a calculation using the Unix utility bc. I often use bc for extended precision calculation, but mostly for simple things [1].

Calculating Apery's constant will require a function to compute binomial coefficients, something not built into bc, and so this post will illustrate how to write custom functions in bc.

(If you wanted to make a serious attempt at setting a record computing Apery's constant, or anything else, you would probably use an extended precision library written in C MPFR or write something even lower level; you would not use bc.)

Apery's series

The series we want to evaluate is

apery_series.svg

To compute this we need to compute the binomial coefficients in the denominator, and to do that we need to compute factorials.

From calculations in the previous post we estimate that summing n terms of this series will give us 2n bits of precision, or 2n/3 decimal places. So if we carry out our calculations to n decimal places, that gives us more precision than we need: truncation error is much greater than numerical error.

bc code

Here's the code, which I saved in the file zeta3.b. I went for simplicity over efficiency. See [2] for a way to make the code much more efficient.

 # inefficient but simple factorial define fact(x) { if (x <= 1) return (1); return (x*fact(x-1)); } # binomial coefficient n choose k define binom(n, k) { return (fact(n) / (fact(k)*fact(n-k))); } define term(n) { return ((-1)^(n-1)/(n^3 * binom(2*n, n))) } define zeta3(n) { scale = n sum = 0 for (i = 1; i <= n; ++i) sum += term(i); return (2.5*sum); }

Now say we want 100 decimal places of (3). Then we should need to sum about 150 terms of the series above. Let's sum 160 terms just to be safe. I run the code above as follows [3].

 $ bc -lq zeta3.b zeta3(160)

This returns

 1.202056903159594285399738161511449990764986292340498881792271555341\83820578631309018645587360933525814493279797483589388315482364276014\64239236562218818483914927
How well did we do?

I tested this by computing (3) to 120 decimals in Mathematica with

 N[RiemannZeta[3], 120]

and subtracting the value returned by bc. This shows that the error in our calculation above is approximately 10-102. We wanted at least 100 decimal places of precision and we got 102.

Notes

[1] I like bc because it's simple. It's a little too simple, but given that almost all software errs on the side of being too complicated, I'm OK with bc being a little too simple. See this post where I used (coined?) the phrase controversially simple.

[2] Not only is the recursive implementation of factorial inefficient, computing factorials from scratch each time, even by a more efficient algorithm, is not optimal. The more efficient thing to do is compute each new coefficient by starting with the previous one. For example, once we've already computed the binomial coefficient (200, 100), then we can multiply by 202*201/101^2 in order to get the binomial coefficient (202, 101).

Along the same lines, computing (-1)^(n-1) is wasteful. When bootstrapping each binomial coefficient from the previous one, multiply by -1 as well.

[3] Why the options -lq? The -l option does two things: it loads the math library and it sets the precision variable scale to 20. I always use the -l flag because the default scale is zero, which lops off the decimal part of all floating point numbers. Strange default behavior! I also often need the math library. Turns out -l wasn't needed here because we explicitly set scale in the function zeta3, and we don't use the math library.

I also use the -q flag out of habit. It starts bc in quiet mode, suppressing the version and copyright announcement.

The post Functions in bc first appeared on John D. Cook.6M6nGALOJp8
External Content
Source RSS or Atom Feed
Feed Location http://feeds.feedburner.com/TheEndeavour?format=xml
Feed Title John D. Cook
Feed Link https://www.johndcook.com/blog
Reply 0 comments