debkeepr integrates non-decimal currencies that use tripartite and tetrapartite systems into the methodologies of Digital Humanities and the practices of reproducible research. The package makes it possible for historical non-decimal currencies, such as the tripartite system of pounds, shillings, and pence, to behave like decimalized numeric values through the implementation of thedeb_lsd,deb_tetra, anddeb_decimal vector types. These types are based on the infrastructure provided by thevctrs package.debkkeepr simplifies the process of performing arithmetic calculations with non-decimal currencies — such as adding £3 13s. 4d. sterling to £8 15s. 9d. sterling — and also provides a basis for analyzing account books with thousands of transactions recorded in non-decimal currencies. The name of thedebkeepr package derives from this latter capability of analyzing historical account books that often useddouble-entry bookkeeping.
Installation
Install the released version of debkeepr from CRAN:
install.packages("debkeepr")Or install the development version from GitHub with:
# install.packages("pak")pak::pak("jessesadler/debkeepr")Please open anissue if you have any questions, comments, or requests.
Historical Background
Thedebkeepr package uses the nomenclature ofl, s, and d to represent pounds, shillings, and pence units in non-decimal currencies. The abbreviations derive from the Latin termslibra,solidus, anddenarius. Thelibra was a Roman measurement of weight, while thesolidus anddenarius were both Roman coins. Thedenarius was a silver coin from the era of the Republic, in contrast to the goldensolidus that was issued in the Late Empire. As the production of silver coins overtook that of gold by the 8th century, asolidus came to represent 12 silverdenarii coins, and 240denarii were — for a time — made from onelibra or pound of silver. The custom of counting coins in dozens (solidi) and scores of dozens (librae) spread throughout the Carolingian Empire and became ingrained in much of Europe. However, a variety of currencies or monies of account usedother bases for thesolidus anddenarius units. Some currencies and other value systems, such as those for weights, added a fourth unit.debkeepr provides a consistent manner for dealing with any set of bases within tripartite or tetrapartite systems through thebases attribute ofdeb_lsd,deb_tetra, anddeb_decimal vectors.
Translations oflibra,solidus, anddenarius units:
- English: pounds, shillings, pence
- French: livres, sols or sous, deniers
- Italian: lire, soldi, denari
- Flemish: ponden, schellingen, groten
- Dutch: guilders, stuivers, penningen
Resources
- Getting Started with debkeepr vignette: An introduction to the
deb_lsd,deb_tetra, anddeb_decimaltypes and their use as vectors and as columns in data frames. - Transactions in Richard Dafforne’s Journal vignette: Examples of financial and arithmetic calculations dealing with various currencies taken from the practice journal in Richard Dafforne’sMerchant’s Mirrour (1660), a 17th-century textbook for learning accounting practices.
- Analysis of Richard Dafforne’s Journal and Ledger vignette: An analysis of the practice journal and ledger in Dafforne’sMerchant’s Mirrour using the
dafforne_transactionsanddafforne_accountsdata provided indebkeepr. - A PDF copy of Dafforne’s practice journal can be consulted to further investigate the practices of early modern double-entry bookkeeping.
Usage
Thedeb_lsd,deb_tetra, anddeb_decimal types are implemented to deal with two interrelated problems inherent in historical non-decimal currencies and other value systems.
- Historical currencies consist of three or four separate non-decimalunits. Most often: pounds, shillings, and pence with sometimes a fourth unit, such as the farthing, added on.
- Thebases of the shillings, pence, and optionally farthing units differed by region, coinage, and era.
Thedeb_lsd type maintains the tripartite structure of non-decimal currencies and provides abases attribute to record the bases for the shillings and pence units. Thedeb_tetra type extends the concept of thedeb_lsd type to incorporate currencies and other types of values that consist of four units. Thedeb_decimal type provides a means to decimalize bothdeb_lsd anddeb_tetra types while keeping track of the two or three non-decimalbases and theunit represented as attributes.
Let’s see how this works in practice, beginning withdeb_lsd vectors. Note that all of the functions indebkeepr begin with the prefixdeb_, which is short for double-entry bookkeeping.
library(debkeepr)# Create deb_lsd vectors with standard bases of 20s. 12d.lsd1<-deb_lsd(l=3, s=13, d=4)lsd2<-deb_lsd(l=8, s=15, d=9)# Combine multiple values togetherc(lsd1,lsd2)#> <deb_lsd[2]>#> [1] 3:13s:4d 8:15s:9d#> # Bases: 20s 12ddeb_tetra vectors work similarly but add anf unit that defaults to a base of four.
# Create deb_tetra vectors with standard bases of 20s. 12d. 4f.tetra1<-deb_tetra(l=3, s=13, d=4, f=3)tetra2<-deb_tetra(l=8, s=15, d=9, f=2)A primary reason for the creation of thedeb_lsd anddeb_tetra types is to simplify arithmetic calculations with non-decimal currency. Doing calculations by hand requires the use ofcompound unit arithmetic and normalization.

All implemented arithmetic calculations withdeb_lsd anddeb_tetra types —sum(),round(),+,-, etc. — automatically normalize the values according to thebases attribute. In addition, you can manually normalize non-standard values withdeb_normalize().
# Perform arithmeticlsd1+lsd2#> <deb_lsd[1]>#> [1] 12:9s:1d#> # Bases: 20s 12dlsd2-lsd1#> <deb_lsd[1]>#> [1] 5:2s:5d#> # Bases: 20s 12dlsd2*2-lsd1#> <deb_lsd[1]>#> [1] 13:18s:2d#> # Bases: 20s 12dtetra2+tetra1#> <deb_tetra[1]>#> [1] 12:9s:2d:1f#> # Bases: 20s 12d 4f# Normalize a non-standard value to default basesdeb_normalize(deb_lsd(132,53,35))#> <deb_lsd[1]>#> [1] 134:15s:11d#> # Bases: 20s 12d# Can also normalize numeric vectors of length 3 or 4# Must provide the bases for tetrapartite valuedeb_normalize(c(132,53,35,18), bases=c(20,12,4))#> <deb_tetra[1]>#> [1] 134:16s:3d:2f#> # Bases: 20s 12d 4fAll types allow the user to define the bases for thesolidus,denarius, and optionally farthing units of values, enabling integration of currencies that do not use the standardized bases. For example, the Polish florin found in Dafforne’s practice journal used the non-standard bases of 30 gros of 18 denars.
# Create deb_lsd vector with standard bases of 20s. 12d.(lsd3<-deb_lsd(l=c(28,32,54,18), s=c(15,8,18,12), d=c(8,11,7,9)))#> <deb_lsd[4]>#> [1] 28:15s:8d 32:8s:11d 54:18s:7d 18:12s:9d#> # Bases: 20s 12d# Same numerical values as Polish florins(florins<-deb_lsd(l=c(28,32,54,18), s=c(15,8,18,12), d=c(8,11,7,9), bases=c(30,18)))#> <deb_lsd[4]>#> [1] 28:15s:8d 32:8s:11d 54:18s:7d 18:12s:9d#> # Bases: 30s 18d# Different outcome with sum due to the different basessum(lsd3)#> <deb_lsd[1]>#> [1] 134:15s:11d#> # Bases: 20s 12dsum(florins)#> <deb_lsd[1]>#> [1] 133:24s:17d#> # Bases: 30s 18d# Vectors with different bases cannot be combined since# their relationship is unknown. Doing so results in an error.sum(lsd3,florins)#> Error:#> ! Incompatible `bases`.#> ℹ `bases` must be compatible to combine <deb_lsd>, <deb_tetra>, or#> <deb_decimal> vectors.#> ✖ Cannot combine: `..1` <deb_lsd> vector with `bases` s = 20 and d = 12.#> ✖ Cannot combine: `..2` <deb_lsd> vector with `bases` s = 30 and d = 18.#> ℹ Use `deb_convert_bases()` to convert one or more of the vectors to compatible#> `bases`.deb_decimal vectors represent non-decimal values in the more familiar decimal form. Internally,deb_decimal vectors are built ondouble() vectors. These decimalized vectors are linked to their non-decimal form through theunit andbases attributes. They can represent either tripartite or tetrapartite values. The only differences are the length of thebases (2 or 3) and the option to choose the “f” unit with tetrapartite values.
# Create deb_decimal from numeric vector(dec1<-deb_decimal(c(5.525,12.235,8.45)))#> <deb_decimal[3]>#> [1] 5.525 12.235 8.450#> # Unit: libra#> # Bases: 20s 12d# Same currency values in solidus unit(dec2<-deb_decimal(c(110.5,244.7,169), unit="s"))#> <deb_decimal[3]>#> [1] 110.5 244.7 169.0#> # Unit: solidus#> # Bases: 20s 12d# Equality between different unitsdec1==dec2#> [1] TRUE TRUE TRUE# Use the bases argument to create tetrapartite valuesdeb_decimal(c(5.525,12.235,8.45), bases=c(20,12,4))#> <deb_decimal[3]>#> [1] 5.525 12.235 8.450#> # Unit: libra#> # Bases: 20s 12d 4f# Equality between deb_lsd and deb_decimal vectors# £5 10s. 6d. is equal to 1,326 pencedeb_lsd(5,10,6)==deb_decimal(1326, unit="d")#> [1] TRUE# Which is also equal to 5,304 farthings with default tetrapartite basesdeb_lsd(5,10,6)==deb_decimal(5304, unit="f", bases=c(20,12,4))#> [1] TRUEWhen working with decimalized data is preferable, thedeb_decimal type makes casting from and todeb_lsd ordeb_tetra possible without losing any metadata about thebases and therefore the actual value being represented.deb_lsd,deb_tetra, anddeb_decimal vectors can also be combined with numeric vectors or cast from and to numeric vectors.debkeepr uses an internalconversion hierarchy ofnumeric() ->deb_decimal() ->deb_tetra ->deb_lsd().
# deb_decimal -> deb_lsdc(dec1,lsd1,lsd2)#> <deb_lsd[5]>#> [1] 5:10s:6d 12:4s:8.4d 8:9s:0d 3:13s:4d 8:15s:9d#> # Bases: 20s 12d# deb_decimal -> deb_tetrac(dec1,tetra1,8.25)#> <deb_tetra[5]>#> [1] 5:10s:6d:0f 12:4s:8d:1.6f 8:9s:0d:0f 3:13s:4d:3f 8:5s:0d:0f#> # Bases: 20s 12d 4f# deb_decimal -> deb_tetra -> deb_lsdc(dec1,tetra1,lsd2)#> <deb_lsd[5]>#> [1] 5:10s:6d 12:4s:8.4d 8:9s:0d 3:13s:4.75d 8:15s:9d#> # Bases: 20s 12d# Cast between deb_lsd, deb_tetra, and deb_decimal vectorsdeb_as_lsd(dec1)#> <deb_lsd[3]>#> [1] 5:10s:6d 12:4s:8.4d 8:9s:0d#> # Bases: 20s 12ddeb_as_decimal(florins)#> <deb_decimal[4]>#> [1] 28.51481 32.28704 54.61296 18.41667#> # Unit: libra#> # Bases: 30s 18ddeb_as_decimal(tetra2)#> <deb_decimal[1]>#> [1] 8.789583#> # Unit: libra#> # Bases: 20s 12d 4f# Provide an f unit base to cast from tripartite to tetrapartitedeb_as_tetra(lsd1, f=4)#> <deb_tetra[1]>#> [1] 3:13s:4d:0f#> # Bases: 20s 12d 4f# Represented by solidus/shillings unitdeb_as_decimal(lsd3, unit="s")#> <deb_decimal[4]>#> [1] 575.6667 648.9167 1098.5833 372.7500#> # Unit: solidus#> # Bases: 20s 12d# Only tetrapartite values can be represented by the farthings unitdeb_as_decimal(tetra1, unit="f")#> <deb_decimal[1]>#> [1] 3523#> # Unit: farthing#> # Bases: 20s 12d 4f# All three types can be cast to base numeric, which,# of course, leads to the loss of all metadataas.numeric(lsd3)#> [1] 28.78333 32.44583 54.92917 18.63750as.numeric(tetra1)#> [1] 3.669792as.numeric(dec1)#> [1] 5.525 12.235 8.450Comparingdeb_lsd,deb_tetra, anddeb_decimal vectors
See theGetting Started with debkeepr vignette for an in depth discussion of the similarities and differences between the two types.
- The
deb_lsdanddeb_tetratypes have the advantage of maintaining the structure and values used by non-decimal currencies, making it easier to identify and present such values. deb_decimalimplements a wider array of mathematical functions and arithmetic operations thandeb_lsdordeb_tetra.- You can move between
deb_lsdordeb_tetratypes and thedeb_decimaltype without losing any data throughdeb_as_lsd(),deb_as_tetra(), anddeb_as_decimal()casting methods. - Because
deb_lsd,deb_tetra, anddeb_decimalare based on thevctrs package, all types act as expected in data frames ortibbles columns. Fromdplyr 1.0.0 — which is the minimal version used by debkeepr — all dplyr functions work on bothdebkeeprtypes. - ggplot2 does not know how to pick a scale for
deb_lsdordeb_tetratypes. In contrast,deb_decimalvectors work properly withggplot2, though explicitly identifying the scale as continuous — withscale_y_continuous()orscale_x_continuous()— is needed to avoid the appearance of a message. deb_lsd,deb_tetra, anddeb_decimalvectors cannot be combined in a single function if theirbasesdiffer. Tripartite and tetrapartite values can be combined if the bases of theirsolidus anddenarius bases match. The only way to transform the bases ofdeb_lsd,deb_tetra, anddeb_decimalvectors is explicitly withdeb_convert_bases(). This prevents mistakenly combining two different currencies together without properly converting their values.
