## cambl

2018-12-10

A library for working with financial amounts involving multiple commodities.

### Upstream URL

### Author

### Maintainer

### License

*Commoditized Amounts and Balances*\\

This library provides a convenient facility for working with commoditized values. It does not allow compound units -- and so is not suited for scientific operations -- but does work rather nicely for the purpose of financial calculations.

The primary entry point to using this library is the creation of
*VALUES*, which may be of many different types. These *VALUES* are
then used as arguments to a set of basic mathematical *OPERATIONS*,
which also yield *VALUES*. However, the type of the result may not be
the same type as either of the operands.

For example, let's say you want to create a figure representing 10 US
dollars. You then add an *INTEGER* to this amount, the number 200. The
result of such an operation will be an amalgam of the two units
involved: Dollars, and No-units. This dual-commodity value is
represented as a *BALANCE* object, whose printed form shows each
commodity amount on its own line. For example:

```
(let ((value (cambl:amount "$100.00")))
(princ (cambl:format-value (cambl:add value 200))))
=> 200
$100.00
```

This library aims to provide convenient access to commoditized math; that is: math involving commodity units. Unlike scientific units, there is no concept of "compound" units. If you divide 1kg by 1m, you do not get "1 kg/m", but "1 kg" (the unit of the second operand is ignored for multiplication and division). The intended use of this library is in situations such as computing financial transactions.

# 1Amounts

There are just a few main entry points to the **CAMBL** library for
dealing with amounts (which is mainly how you'll use it). Here is
a quick list, following by a description in the context of a REPL
session. Note that where the name contains value, it will work for
integers, amounts and balances. If it contains amount or balance, it
only operates on entities of that type.

Function | Description |
---|---|

amount[*] | create an amount from a string |

exact-amount | create an amount from a string which overrides |

its commodity's display precision; this feature | |

"sticks" through any math operations | |

parse-amount[*] | parse an amount from a string (alias for 'amount') |

read-amount[*] | read an amount from a stream |

read-exact-amount | read an exact amount from a stream |

format-value | format a value to a string |

print-value | print a value to a stream |

add | perform math using values; the values are |

subtract | changed as necessary to preserve information |

multiply | (adding two amounts may result in a |

divide | balance). |

value-zerop | would the value display as zero? |

value-zerop* | is the value truly zero? |

value-minusp | would the amount display as a negative amount? |

value-minusp* | is the amount truly negative? |

value-plusp | would it display as an amount greater than zero? |

value-plusp* | is it truly greater than zero? |

value= | compare two values |

value/= | |

value< | compare values (not meaningful for all values, |

value<= | such as balances) |

value> | |

value>= | |

value-equal | compare two values for exact match |

value-equalp | compare two values only after rounding to what |

would be shown to the user (approximate match) | |

-- this is the same as value= | |

value-not-equal | compare if two values for not an exact match |

value-not-equalp | compare two values after commodity rounding |

value-lessp | same as value< |

value-lessp* | compare if a < b exactly, with full precision |

value-lesseqp | same as value<= |

value-lesseqp* | exact version of value<= |

value-greaterp | same as value> |

value-greaterp* | exact version of value> |

value-greatereqp | same as value>= |

value-greatereqp* | exact version of value>= |

amount-precision | return the internal precision of an amount |

display-precision | return the "display" precision for an amount |

or a commodity |

# 2Example Session

Interacting with **CAMBL** begins with creating an amount. This is done
most easily from a string, but it can also be read from a stream:

```
(cambl:amount "$100.00")
=> #<CAMBL:AMOUNT "$100.00" :KEEP-PRECISION-P NIL>
(with-input-from-string (in "$100.00")
(cambl:read-amount in))
=> #<CAMBL:AMOUNT "$100.00" :KEEP-PRECISION-P NIL>
```

When you parse an amount using one of these two functions, **CAMBL**
creates a *COMMODITY* class for you, whose symbol name is "$". This
class remembers details about how you used the commodity, such as the
input precision and the format of the commodity symbol. Some of these
details can be inspected by looking at the amount's commodity
directly:

```
(cambl:amount-commodity (cambl:amount "$100.00"))
=> #<CAMBL::COMMODITY #S(CAMBL::COMMODITY-SYMBOL
:NAME $
:NEEDS-QUOTING-P NIL
:PREFIXED-P T
:CONNECTED-P T)
:THOUSAND-MARKS-P NIL :DISPLAY-PRECISION 2>
```

Here you can see that the commodity for $100.00 is $, and it knows that the commodity should be prefixed to the amount, and that it gets connected to the amount. This commodity was used without any "thousand marks" (i.e. $1000.00 vs $1,000.00), and it has a maximum display precision of TWO observed so far. If we print such an amount, we'll see the same style as was input:

```
(cambl:format-value (cambl:amount "$100.00"))
=> "$100.00"
(cambl:print-value (cambl:amount "$100.00"))
=> NIL
$100.00
```

**CAMBL** observed how you used the "$" commodity, and now reports back
all dollar figures after the same fashion. Even though there are no
cents in the amounts above, **CAMBL** will still record a full two
digits of precision (this becomes important during division, to guard
against fractional losses during repeated rounding).

```
(cambl:amount-precision (cambl:amount "$100.00"))
=> 2
```

**CAMBL** remembers the greatest precision it has seen thus far, but
never records a lesser precision. So if you parse $100.00 and then
$100, both values will be printed as $100.00.

There are three functions for creating amounts, but they have some
subtle differences where precision is concerned. They are: `amount`

,
`amount*`

, and `exact-amount`

. Here are the differences:

```
(cambl:amount "$100.00")
=> #<CAMBL:AMOUNT "$100.00" :KEEP-PRECISION-P NIL>
```

- amount has an internal precision of 2
- commodity $ has a display precision of 2 (if no otheramount using a higher precision was observed so far)
- when printing, amount uses the commodity's precision

```
(cambl:format-value *)
=> "$100.00"
(cambl:format-value ** :full-precision-p t)
=> "$100.00"
```

```
(cambl:amount* "$100.0000")
=> #<CAMBL:AMOUNT "$100.0000" :KEEP-PRECISION-P NIL>
```

- amount has an internal precision of 4
- commodity $ still has a display precision of 2 (from above)
- when printing, amount uses the commodity's precision

```
(cambl:format-value *)
=> "$100.00"
(cambl:format-value ** :full-precision-p t)
=> "$100.0000"
```

```
(cambl:exact-amount "$100.0000")
=> #<CAMBL:AMOUNT "$100.0000" :KEEP-PRECISION-P T>
```

- amount has an internal precision of 4
- commodity $ still has a display precision of 2 (from above)
- when printing, amount uses its internal precision

```
(cambl:format-value *)
=> "$100.0000"
(cambl:format-value ** :full-precision-p t)
=> "$100.0000"
```

There are similar variants for the stream reading functions:

`read-amount`

`read-amount*`

`read-exact-amount`

Internally, an amount's quantity is stored as a rational number, and
therefore has a perfect precision. The internal precision field of an
amount tries to keep track of the number of decimals to display when
printing a value with the `FULL-PRECISION-P`

option.

By default, uncommoditized amounts (which are in fact just rational
numbers), are displayed with a precision of 3. This can be changed by
setting `CAMBL:*DEFAULT-DISPLAY-PRECISION*`

. When they are used in
math operations, their considered internal precision to compute the
result's internal precision is at most `CAMBL:*EXTRA-PRECISION*`

(which is 6 by default).

NOTE: The `KEEP-PRECISION-P`

property of an amount carries through
any math operations involving that amount, so that the final result is
always displayed using its own internal percision.

The point of all this is that amounts are displayed as the user expects them to be, but internally never lose information. In fact, if you divide two high internal precision amounts together, you'll get a new amount with a very high internal precision, but which still displays as expected:

```
(setf *tmp* (cambl:divide (cambl:amount "$100.00")
(cambl:amount "50000000")))
(cambl:format-value *tmp* :full-precision-p t)
=> "$0.0000020000000000"
(cambl:format-value *tmp*)
=> "$0.00"
```

You'll notice here that the amount displayed is not
$0.00000200000000002. This is because **CAMBL** does not try to capture
every digit resulting from a division; rather, it keeps six more
digits of precision than is strictly necessary so that even after
millions of calculations, not a penny is lost. If you find this is not
enough slack for your calculations, you can set
`CAMBL:*EXTRA-PRECISION*`

to a higher or lower value.

# 3Commodities

**CAMBL** offers several methods for accessing the commodity information
relating to amounts:

Function | Description |
---|---|

amount-commodity | the COMMODITY referenced by an amount |

display-precision | display precision of an AMOUNT or COMMODITY |

commodity-qualified-name | the name used print a COMMODITY |