class FinancialCalculator::Pv

Calculate the present value of a series of equal of payments

Attributes

future_value[R]

@return [Numeric] The value remaining after the final payment has been made

num_periods[R]

@return [Numeric] The number of periodic payments

payment[R]

@return [Numeric] The amount of the periodic payment

rate[R]

@return [Numeric] The discount rate used in the calculation

result[R]

@return [Numeric] The result of the present value calculation

Public Class Methods

new(rate, num_periods, payment, future_value = 0, pay_at_beginning = false) click to toggle source

Create a new present value calculation

@see en.wikipedia.org/wiki/Present_value @example

FinancialCalculator::Pv.new(0.02, 10, -100) #=> PresentValue(898.2585006242236)

@param [Numeric] rate The discount (interest) rate to use @param [Numeric] num_periods The number of periodic payments @param [Numeric] payment The amount of the periodic payment @param [Numeric] future_value The value remaining after the final payment has been made @param [Boolean] pay_at_beginning Whether the payments are made at the beginning or end of each period @return [FinancialCalculator::Pv] A Pv object @raise [ArgumentError] Raises an ArgumentError if num_periods is less than 0 or a required numeric

field is given a non-numeric value
# File lib/financial_calculator/pv.rb, line 34
def initialize(rate, num_periods, payment, future_value = 0, pay_at_beginning = false)
  validate_numerics(rate: rate, num_periods: num_periods, payment: payment, future_value: future_value)

  if num_periods < 0
    raise ArgumentError.new('Cannot calculate present value with negative periods. Use future value instead.')
  end

  @rate             = Flt::DecNum(rate.to_s)
  @num_periods      = Flt::DecNum(num_periods.to_s)
  @payment          = Flt::DecNum(payment.to_s)
  @future_value     = Flt::DecNum(future_value.to_s)
  @pay_at_beginning = pay_at_beginning
  @result           = solve(@rate, @num_periods, @payment, @future_value, pay_at_beginning)
end

Public Instance Methods

inspect() click to toggle source
# File lib/financial_calculator/pv.rb, line 49
def inspect
  "PV(#{result})"
end
pays_at_beginning?() click to toggle source

@return [Boolean] Whether the payments are made at the beginning of each period

# File lib/financial_calculator/pv.rb, line 54
def pays_at_beginning?
  @pay_at_beginning
end

Private Instance Methods

discount(amount, rate, periods) click to toggle source
# File lib/financial_calculator/pv.rb, line 71
def discount(amount, rate, periods)
  return 0 if amount.zero?
  amount / (1 + rate) ** periods 
end
solve(rate, num_periods, payment, future_value, pay_at_beginning) click to toggle source
# File lib/financial_calculator/pv.rb, line 60
def solve(rate, num_periods, payment, future_value, pay_at_beginning)
  start_period  = pay_at_beginning ? 0 : 1
  end_period    = pay_at_beginning ? num_periods - 1 : num_periods

  present_value = (start_period..end_period.abs).reduce(Flt::DecNum('0')) do |total, t|
    total += discount(payment, rate, t)
  end

  -(present_value + discount(future_value, rate, num_periods))
end