 02 Nov 2021

# Calculating on the Command Line

Note: there's a public repository containing the source code and any formal documentation for the program that this post is about.

There are any number of ways to get your computer to do math, but I wanted a command line program to quickly, easily and in as natural a way as possible do basic calculations like summing a few numbers, calculating an item's after-tax price or doing basic unit conversions. I also wanted it to operate on both integer and real values and give results to a reasonable number of decimal places.

Of course, I wasn't going to implement the part that did the actual math since existing programs already do that. One of the earliest versions of my `calc` script was just a minimal wrapper around one such program: `bc`. Aside from code to output a usage message my script's implementation was basically

```echo "scale=2; \$*" | bc
```

which combined all of the command line arguments into a single expression for `bc` to evaluate, after setting the default number of digits after the decimal to 2 (which is sufficient for most calculations and ideal for ones involving (my local) currency). Note that the result from `bc` may be an integer or may have fewer or more than the default number of digits after the decimal depending on what's appropriate for the particular computation.

(Also note that the default number of digits after the decimal affects intermediate as well as final results of calculations, and so the result of a calculation with fewer digits after the decimal may not just be a rounded - or even truncated - version of the result of the same calculation done with more digits after the decimal.)

This version worked pretty well, especially with `=` (that is, a single equals sign) as a symbolic link to `calc`:

```= 2 + 2
= 12.34 + 56.78 + 90.12
= 5 / 3
= '42.5 * 17'
= 42.5 \* 17
```
 4 159.24 1.66 722.5 722.5

Having to quote or escape multiplication signs to protect them from being expanded by the shell into every file in the current directory was less than ideal, but a simple - if a little brute-force - change

```echo "scale=2; \$*" | tr 'x' '*' | bc
```

fixed that. Now the 'x' character could be used as a multiplication sign as well:

```= 42.5 x 17
```
```722.5
```

So now the four basic mathematical operations could be used without having to quote or escape anything. Parentheses still required - and still do require - escaping or (usually easier) quoting, however:

```= '(23.40 + 12.34) x 1.12'
```
```40.02
```

The final tweak - until very recently - was to allow the default number of digits after the decimal to be customized on a per-session or a per-command basis. The implementation effectively became

```echo "scale=\${CALC_SCALE:-2}; \$*" | tr 'x' '*' | bc
```

which allowed the `CALC_SCALE` environment variable to be used to specify that default:

```= 5 / 3
export CALC_SCALE=4
= 5 / 3
CALC_SCALE=8 = 5 / 3
= 5 / 3
CALC_SCALE=
= 5 / 3
```
 1.66 1.6666 1.66667 1.6666 1.66

And that's where it stood until I looked at it again in preparation for writing this post. While it's still not a very long script its core is definitely no longer a one-liner. But calculations can now include the mathematical constants `pi` and `e`, as well as the `sin()`, `cos()`, `atan()`, `ln()` and `exp()` functions, and the default number of digits after decimal is now easier to customize:

• the `CALC_SCALE` environment variable's name was too long for convenient use on the command line, so the `sc` environment variable can also be used: `sc` is intended for use with a single invocation of `calc`, while `CALC_SCALE` should be used over larger scopes
• if the program's basename is an equals sign (=) preceded by one, two or three digits then the number that those digits represent will be the default number of digits after the decimal

(A program can be given an additional basename by creating a symbolic link to it: for example, executing `ln -s calc 15=` will create a symbolic link that can be used to perform calculations with a default of 15 digits after the decimal place.)

So calculations like the following are now possible:

```= 2 x pi x pi
export CALC_SCALE=5
= 2 x pi x pi
sc=8 = 2 x pi x pi
= 2 x pi x pi
8= 2 x pi x pi
9= 'sin(1.2) x sin(1.2) + cos(1.2) x cos(1.2)'
sc=10 = pi
```
 19.71 19.7392 19.7392 19.7392 19.7392 1 3.14159

Will I use this additional functionality often enough to warrant the added complexity? I'm not sure. But if I didn't add it then there wouldn't be any way for me to find out. It's not a huge increase in absolute complexity in this case (even if it is in relative complexity), but I think the same reasoning applies to other, larger programs as well. Of course, I could always remove the new code if it turns out I don't use it, but who ever does that?

As a final note, Emacs users can use the `quick-calc` command to access similar functionality, as I recently found out. Well, rediscovered actually, since it turns out that I've had a keybinding for it in my Emacs configuration since 2018 and had completely forgotten about it: a not uncommon occurrence.

## Selected Commit History

Some selected dates in the `calc` script's original commit history (which is different from its GitHub commit history):

• <2007-07-16 Mon> initial commit
• <2015-08-31 Mon> can use 'x' in place of '*'
• <2017-03-31 Fri> can use environment variable to set digits after decimal
• <2021-11-24 Wed> can use shorter `sc` environment variable
• <2021-11-25 Thu> can use pi, e, sin(), cos(), atan(), ln() and exp() in calculations

If you'd like to support this site then check out my web app InEveryNook.com and see if it's of interest to you, pass it along to anyone you think might be interested in it, or both. Thanks!