decimal

R-CMD-check coverage

Overview

decimal provides exact, arbitrary-precision decimal vectors for R. If you’ve ever been surprised that 0.1 + 0.2 == 0.3 is FALSE, this package is for you:

library(decimal)

0.1 + 0.2 == 0.3
#> [1] FALSE
decimal("0.1") + decimal("0.2") == decimal("0.3")
#> [1] TRUE

Doubles are binary fractions, so they can’t represent most decimal numbers exactly, and tiny errors accumulate as you compute. That’s usually fine — but not when you’re working with money, invoices, exchange rates, or anything else where cents have to add up. decimal uses a decimal representation and performs arithmetic under an explicit decimal context, so any rounding is controlled and observable.

Under the hood, decimal is built on:

Highlights:

Installation

Install the released version from CRAN:

install.packages("decimal")

Usage

Create decimal vectors from strings (exact, and the recommended way) or integers, and use them like any other numeric vector:

library(decimal)

x <- decimal(c("1.20", "2.30", "3.40"))
x
#> <decimal[3]>
#> [1] 1.20 2.30 3.40

sum(x)
#> <decimal[1]>
#> [1] 6.90
mean(x)
#> <decimal[1]>
#> [1] 2.30

Decimal vectors are first-class citizens in tibbles and dplyr pipelines:

library(dplyr)

sales <- tibble::tibble(
  item  = c("coffee", "bagel", "juice"),
  price = decimal(c("2.50", "1.25", "3.95")),
  qty   = c(3L, 2L, 1L)
)

sales |>
  mutate(total = price * qty) |>
  summarise(revenue = sum(total))
#> # A tibble: 1 × 1
#>   revenue
#>     <dec>
#> 1   13.95

Exactness matters most when small errors compound — literally, in the case of interest:

principal <- decimal(c("1000.00", "2500.00", "500.00"))
rate <- decimal("0.05")

balance <- principal * (1L + rate)^4L
balance
#> <decimal[3]>
#> [1] 1215.5062500000 3038.7656250000 607.7531250000

# round to cents for reporting
quantize(balance, decimal("0.01"))
#> <decimal[3]>
#> [1] 1215.51 3038.77 607.75

Learning more

License

decimal is MIT licensed. The vendored mpdecimal library retains its own BSD-2-Clause terms; see inst/COPYRIGHTS.