I was recently reminded of the ability of Emacs Calc to perform computations on values with units. Like so many Emacs features, it was on the list of the things I wanted to explore. Today is the day to do so!

## Basic operations with units

The Emacs Calc manual presents a lot of features but makes it hard to
understand how to start. You cannot just enter an expression such as “25mm” in
`calc-mode`

: 25 will be correctly interpreted as a number, but “mm” will be
used to trigger the `m m`

key binding which executes `calc-save-modes`

. Not
what you had in mind.

To enter a value with a unit, use the `'`

(apostrophe) key to enter an
algebraic expression and hit `return`

to push it on the stack. You can now use
this value for your computations.

Note that after hitting `'`

, you can use it a second time to recall the
expression on the stack and edit it.

To remove the unit associated with a value. Simply hit `u r`

, for “**u**nit
**r**emove”.

### Simplifying expressions

Expressions containing multiple units can be simplified. For example, enter
two values, `2m`

and `50cm`

and add them with `+`

. The resulting expression is
`2 m + 50 cm`

. Hit `u s`

, for “**u**nit **s**implify”, to have Calc simplify
it to `2.5 m`

.

### Converting units

Unit conversion is of course possible. Use `u c`

, for “**u**nit **c**onvert”,
at any moment: Calc will ask for a unit and will try to convert the value at
the top of the stack into this unit. For example, entering `1.5mi`

(`mi`

being
the unit for miles) and typing `u c km <return>`

will correctly yield
`2.414016 km`

.

You will quickly discover that Calc tries way too hard to convert units and
will produce really strange results when types are not compatible. For
example, trying to convert `250mA`

into kilometers will produce `0.25A`

which
is clearly incorrect. I have no idea what causes this behaviour. Fortunately
you can use `u n`

, bound to `calc-convert-exact-units`

, which will check that
the unit you required is compatible with the unit of the expression on the
stack. To minimize the risk of producing incorrect results by mistake, I
replace the `calc-convert-units`

function by `calc-convert-exact-units`

. I
would prefer to remap `u c`

, but Calc has a strange way to handle key bindings
that prevent doing this kind of remapping.

```
(use-package calc
:config
(require 'calc-units)
(setf (symbol-function 'calc-convert-units)
(symbol-function 'calc-convert-exact-units)))
```

As a shortcut, `u b`

, where `b`

stands for “**b**ase”, will convert the value
to its base unit. For example, it will automatically convert `250mA`

to
`0.25A`

.

## Defining custom units

Calc comes by default with more than 170 units (type `u v`

to list them all),
but none of them are about standard data size units. This is disappointing
given that Emacs is a software primarily used for programming. But we can add
new units, so it is not that much of a problem.

New units can be defined with the `math-additional-units`

variable. Its format
is the same as `math-standard-units`

: each entry is a list of three elements:

- A symbol identifying the unit.
- An expression indicating the value of the unit, or
`nil`

for fundamental units. - A textual description.

Let us add data sizes. We need two units, bits and bytes, with bytes being
defined as 8 bits. Note that using the `b`

symbol for the bit unit will
override the internal “Barn” unit; not a problem to me, I do not expect to use
it any time soon. Feel free to use `bit`

instead.

```
(setq math-additional-units
'((b nil "Bit")
(B "8 * b" "Byte")))
(setq math-units-table nil)
```

We need to set `math-units-table`

to `nil`

after defining new units to force
Calc to recompute its internal table.

These new units can of course be used with standard SI prefixes defined in
Calc. For example, `25kB`

will correctly be converted to `25000 B`

. And asking
for a convertion to the base unit will yield `200000 b`

.

A limitation of Calc is its inability to handle unit prefixes of more than one
character, so we cannot define `ki`

as being a prefix with a multiplicative
value of 1024, which would for example allow us to manipulate kibibytes.

A workaround is to define these power-of-two binary units with the prefix included:

```
(setq math-additional-units
'((b nil "Bit")
(B "8 * b" "Byte")
(kiB "2^10 * B" "Kibibyte")
(MiB "2^20 * B" "Mebibyte")
(GiB "2^30 * B" "Gibibyte")
(TiB "2^40 * B" "Tebibyte")
(PiB "2^50 * B" "Pebibyte")
(EiB "2^60 * B" "Exbibyte")))
(setq math-units-table nil)
```

Very helpful for data size conversion.

## Going farther with Calc

Writing this post has been an interesting experience: it forced me to read various parts of the Calc manual and some of its source files. It made me realize that this package is full of useful features. I hope to find the time to experiment with Calc features in the future.