Sometimes you don’t have all the math functions available that you would like. For example, maybe you have a way to calculate natural logs but you would like to calculate a log base 10.

The Unix utility `bc`

is a prime example of this. It only includes six common math functions:

- sine
- cosine
- arctangent
- natural log
- exp
- square root

Users are expected to know how to calculate anything else they need from there. (Inexplicably, `bc`

also includes a way to calculate Bessel functions.)

This post collects formulas that let you bootstrap the functions listed above into all the trig and hyperbolic functions and their inverses.

## Logarithms

Most programming languages provide a way to compute natural logs but not logs in bases other than *e*. If you have a way to compute logs in base *b*, you can compute logs in any other base via

So, for example, you could compute the log base 10 of a number by computing its natural log and dividing by the natural log of 10.

## Exponents

If you have a way to calculate *e*^{x} and natural logs, you can compute *x*^{y} via

Since square roots correspond to exponent 1/2, you can use this to compute square roots.

## Trig functions

If you have a way to calculate sine and cosine, you can calculate the rest of the six standard trig functions.

## Inverse trig functions

If you have a way to calculate inverse tangent, you can bootstrap it to compute the rest of the inverse trig functions.

Also, you can use arctan to compute π since π = 4 arctan(1).

## Hyperbolic functions

If you have a way to compute exponentials, you can calculate hyperbolic functions.

## Inverse hyperbolic functions

If you can compute square roots and logs, you can compute inverse hyperbolic functions.

## Complex branch cuts

Up to this point this post has implicitly assumed we’re only working with real numbers. When working over complex numbers, inverse functions get more complicated. You have to be explicit about which branch you’re taking when you invert a function that isn’t one-to-one.

Common Lisp worked though all this very thoroughly, defining arc tangent first, then defining everything else in a carefully chosen sequence. See Branch cuts and Common Lisp.

Speaking of an enhanced set of bc standard functions, see http://cleverdomain.org/bc

Part of the fun for me with bc is expanding on the basic setup with functions that behave as one would expect when the scale parameter is changed, so that the functions report accurately to the correct number of digits. In many cases an interesting exercise.

I wonder why they didn’t go further: Since you have the “sin” function and “pi”, the “cos” function is clearly redundant. And since you have “exp” and “ln”, you don’t really need “sqrt”.

Is the set {sin, atan2, exp, ln} enough to bootstrap a basic math library for real numbers? Can we do better (in terms of less functions or in terms of “more efficient set of functions”)?

I didn’t go as minimal as possible. I basically went with what’s available in the bc program.

Yes, of course, by “they” I meant “the bc designers” (or, more properly, “the dc designers”).

I was just wondering about the lost of precision and efficiency that results from using such a small math library because the basic idea is very attractive in the microcontroller context but might end up affecting the microcontroller output or its reaction time…