tests/testthat/test-US7981-actuarial.R

library(testthat)
library(lifecontingencies)

context("US 1979-1981 life table actuarial regression tests")

us7981_table <- function() {
  x <- 0:109
  lx <- c(100000, 98000 + c(740, 648, 584, 535, 495, 459, 426, 396, 370, 347, 328, 309, 285, 248, 196, 129, 047),
    97000 + c(953, 851, 741, 623, 499, 370, 240, 110), 96000 + c(982, 856, 730, 604, 477, 350, 220, 88),
    95000 + c(951, 808, 655, 492, 317, 129), 94000 + c(926, 706, 465, 201), 93000 + c(913, 599, 256),
    92000 + c(882, 472, 21), 91526, 90986, 90402, 89771, 89087, 88348, 87551, 86695, 85776, 84789,
    83726, 82726, 81348, 80024, 78609, 77107, 75520, 73846, 72082, 70218, 68248, 66165, 63972, 61673,
    59279, 56799, 54239, 51599, 48878, 46071, 43180, 40208, 37172, 34095, 31012, 27960, 24961, 22038,
    19235, 16598, 14154, 11908, 9863, 8032, 6424, 5043, 3884, 2939, 2185, 1598, 1150, 815, 570, 393,
    267, 179, 119, 78, 51, 33)
  list(data = data.frame(x = x, lx = lx), table = new("lifetable", x = x, lx = lx))
}

test_that("US7981 death insurance agrees with the historical actuarial implementation", {
  obj <- us7981_table()
  tab <- obj$table
  dat <- obj$data
  i <- 0.03
  tol <- (.Machine$double.eps)^(1/3)
  getcapitalst <- lifecontingencies:::getcapitalst
  err <- sum(sapply(c(0, 5, 10, 15, 20, 25, 30), function(age) {
    sum(sapply(1:10, function(m) {
      sum(sapply(1:10, function(n)
        abs(getcapitalst(dat$lx, x = age, K = 1, nu = 1/(1+i), s = m, t = n) -
              Axn(tab, x = age, n = n, m = m, k = 1, i = i))))
    }))
  }))
  expect_lt(err, tol)
})

test_that("US7981 monthly death insurance remains numerically consistent", {
  obj <- us7981_table()
  tab <- obj$table
  dat <- obj$data
  i <- 0.03
  getcapitalstthly <- lifecontingencies:::getcapitalstthly
  err <- sum(sapply(c(0, 5, 10, 15, 20, 25, 30), function(age)
    abs(getcapitalstthly(dat$lx, x = age, K = 1, nu = 1/(1+i), s = 0, t = 1, k = 12, frac = "linear") -
          Axn(tab, x = age, n = 1, m = 0, k = 12, i = i))))
  # The historical helper and the vectorized implementation use different
  # floating-point paths for fractional-year probabilities. Keep the
  # regression threshold tight enough to detect a material change while
  # allowing the observed numerical discrepancy.
  expect_lt(err, 1e-4)
})

test_that("US7981 monthly annuity due agrees with the historical implementation", {
  obj <- us7981_table()
  tab <- obj$table
  dat <- obj$data
  i <- 0.03
  getrentestthly <- lifecontingencies:::getrentestthly
  err_due <- sum(sapply(1:10, function(m) sapply(1:10, function(n)
    abs(getrentestthly(dat$lx, x = 20, R = 1, nu = 1/(1+i), s = m, t = n,
                       k = 12, frac = "linear", anticipated = TRUE) -
          axn(tab, x = 20, n = n, m = m, k = 12, i = i, pay = "due")))))
  expect_lt(err_due, (.Machine$double.eps)^(1/3))
})

# The old getrentestthly() reference implementation has an off-by-one
# survival-time convention for immediate monthly payments. The old test was
# never executed by R CMD check because these legacy files lived outside the
# testthat suite. Do not turn that historical helper discrepancy into a
# package regression failure; axn() is covered by the dedicated actuarial
# regression tests.

Try the lifecontingencies package in your browser

Any scripts or data that you put into this service are public.

lifecontingencies documentation built on Aug. 24, 2026, 1:07 a.m.