finanza/interest

Time-value-of-money helpers built on finanza/decimal.

Every function takes its inputs as decimals, computes in decimal, and rounds the final result with HalfEven (“banker’s”) to the caller-supplied number of decimal places.

Precision

Iterative computations (future_value, present_value, payment, effective_annual_rate, compound_interest) target 7 decimal digits of internal working precision. Before every multiplication inside the iterative growth-factor loop the accumulator is rounded adaptively to the largest digit count for which the resulting product still fits under 2^53 − 1 (the JavaScript safe-integer ceiling enforced by finanza/decimal). For typical inputs the target precision is always reached; only when the growth factor swells (long horizons at very high rates, growth above ~10⁵) does the per-step precision shed digits to keep the multiplication safe.

Concrete consequence: results match textbook 50-digit references (Python decimal, numpy_financial, Excel) to the cent at digits = 2 and to ~10⁻⁶ at digits = 6 for monthly rates and horizons up to about 30 years. For lending-grade work where the answer must be reproducible against external industry tooling, stick to those typical-input ranges or compute the closed form in a higher-precision package.

Types

Errors raised by interest functions.

pub type InterestError {
  NegativePrincipal
  NegativeRate
  PeriodsOutOfRange
  CompoundsOutOfRange
  NegativeDigits
  ArithmeticError(error: decimal.ArithmeticError)
}

Constructors

  • NegativePrincipal

    principal was negative.

  • NegativeRate

    rate was negative.

  • PeriodsOutOfRange

    periods was zero or negative, or exceeded the supported range 1..=1200 (100 years of monthly compounding).

  • CompoundsOutOfRange

    compounds_per_year was zero or negative.

  • NegativeDigits

    digits was negative.

  • ArithmeticError(error: decimal.ArithmeticError)

    Underlying decimal arithmetic produced an error.

Values

pub fn compound_interest(
  principal principal: decimal.Decimal,
  annual_rate annual_rate: decimal.Decimal,
  years years: Int,
  compounds_per_year compounds_per_year: Int,
  digits digits: Int,
) -> Result(decimal.Decimal, InterestError)

Future value under compound interest:

FV = principal × (1 + annual_rate / compounds_per_year)^(compounds_per_year × years)
pub fn effective_annual_rate(
  nominal_rate nominal_rate: decimal.Decimal,
  compounds_per_year compounds_per_year: Int,
  digits digits: Int,
) -> Result(decimal.Decimal, InterestError)

Effective annual rate from a nominal rate compounded compounds_per_year times per year:

EAR = (1 + nominal_rate / compounds_per_year)^compounds_per_year - 1

See the module-level Precision section for the 7-working-digit target and the adaptive overflow guard.

pub fn future_value(
  present present: decimal.Decimal,
  rate_per_period rate_per_period: decimal.Decimal,
  periods periods: Int,
  digits digits: Int,
) -> Result(decimal.Decimal, InterestError)

Future value of present after periods periods at rate_per_period.

See the module-level Precision section for the 7-working-digit target and the adaptive overflow guard.

pub fn payment(
  principal principal: decimal.Decimal,
  rate_per_period rate_per_period: decimal.Decimal,
  periods periods: Int,
  digits digits: Int,
) -> Result(decimal.Decimal, InterestError)

Periodic payment for a fully-amortising loan:

PMT = principal × rate / (1 - (1 + rate)^(-periods))

When rate_per_period is zero, returns straight-line principal / periods.

See the module-level Precision section for the 7-working-digit target and the adaptive overflow guard.

pub fn present_value(
  future future: decimal.Decimal,
  rate_per_period rate_per_period: decimal.Decimal,
  periods periods: Int,
  digits digits: Int,
) -> Result(decimal.Decimal, InterestError)

Present value of future discounted at rate_per_period for periods periods.

See the module-level Precision section for the 7-working-digit target and the adaptive overflow guard.

pub fn simple_interest(
  principal principal: decimal.Decimal,
  rate rate: decimal.Decimal,
  periods periods: Int,
  digits digits: Int,
) -> Result(decimal.Decimal, InterestError)

Simple interest: I = P × r × t.

Search Document