OpenStax Principles of Finance (CC BY 4.0) ยท MIT OCW 15.401 (CC BY-NC-SA 4.0)
A dollar today is worth more than a dollar tomorrow. The discount rate bridges the two: it bundles the cost of waiting, inflation expectations, and risk. Most financial decisions start by comparing present values.
Present value and future value
Future value compounds a present amount forward: FV = PV × (1+r)n. Present value discounts a future amount back: PV = FV / (1+r)n. The discount factor 1/(1+r)n tells you what one future dollar is worth today.
Scheme
; Future value: FV = PV * (1 + r)^n
(define (future-value pv r n)
(* pv (expt (+ 1 r) n)))
; Present value: PV = FV / (1 + r)^n
(define (present-value fv r n)
(/ fv (expt (+ 1 r) n)))
; $1000 at 5% for 10 years
(display "FV of $1000 at 5% for 10yr: $")
(display (round (future-value 10000.0510)))
(newline)
; What is $1629 in 10 years worth today at 5%?
(display "PV of $1629 at 5% for 10yr: $")
(display (round (present-value 16290.0510)))
(newline)
; Discount factor
(define (discount-factor r n)
(/ 1 (expt (+ 1 r) n)))
(display "Discount factor (5%, 10yr): ")
(display (discount-factor 0.0510))
Python
# Future value and present valuedef future_value(pv, r, n):
return pv * (1 + r) ** n
def present_value(fv, r, n):
return fv / (1 + r) ** n
def discount_factor(r, n):
return1 / (1 + r) ** n
fv = future_value(1000, 0.05, 10)
print(f"FV of $1000 at 5% for 10yr: ${fv:.2f}")
pv = present_value(1629, 0.05, 10)
print(f"PV of $1629 at 5% for 10yr: ${pv:.2f}")
print(f"Discount factor (5%, 10yr): {discount_factor(0.05, 10):.6f}")
Compound vs simple interest
Simple interest pays on the original principal only: FV = PV × (1 + r·n). Compound interest pays on accumulated interest too. The gap widens with time. At high rates or long horizons, compounding dominates.
Scheme
; Simple interest: FV = PV * (1 + r*n)
(define (simple-fv pv r n)
(* pv (+ 1 (* r n))))
; Compound interest: FV = PV * (1 + r)^n
(define (compound-fv pv r n)
(* pv (expt (+ 1 r) n)))
; Compare $1000 at 8% for 20 years
(define pv 1000)
(define r 0.08)
(define n 20)
(display "Simple: $") (display (round (simple-fv pv r n))) (newline)
(display "Compound: $") (display (round (compound-fv pv r n))) (newline)
(display "Difference: $")
(display (round (- (compound-fv pv r n) (simple-fv pv r n))))
Python
# Simple vs compound interestdef simple_fv(pv, r, n):
return pv * (1 + r * n)
def compound_fv(pv, r, n):
return pv * (1 + r) ** n
pv, r, n = 1000, 0.08, 20
s = simple_fv(pv, r, n)
c = compound_fv(pv, r, n)
print(f"Simple: ${s:.2f}")
print(f"Compound: ${c:.2f}")
print(f"Difference: ${c - s:.2f}")
Net present value
NPV sums the present values of all cash flows, including the initial outlay (time 0). A positive NPV means the investment creates value — provided the discount rate reflects the true opportunity cost of capital. The core decision rule in corporate finance.
Scheme
; NPV = sum of PV of each cash flow; Cash flows: list of (time . amount) pairs
(define (pv-cashflow cf r)
(/ (cdr cf) (expt (+ 1 r) (car cf))))
(define (npv cashflows r)
(apply + (map (lambda (cf) (pv-cashflow cf r)) cashflows)))
; Project: invest $10,000 now, receive $3,000/yr for 5 years
(define project
(list (cons 0-10000)
(cons 13000) (cons 23000) (cons 33000)
(cons 43000) (cons 53000)))
(display "NPV at 8%: $")
(display (round (npv project 0.08)))
(newline)
(display "NPV at 12%: $")
(display (round (npv project 0.12)))
(newline)
(display "NPV at 15%: $")
(display (round (npv project 0.15)))
Python
# Net Present Valuedef npv(cashflows, r):
"""cashflows: list of (time, amount) tuples"""returnsum(amt / (1 + r) ** t for t, amt in cashflows)
# Invest $10,000, receive $3,000/yr for 5 years
project = [(0, -10000)] + [(t, 3000) for t inrange(1, 6)]
for rate in [0.08, 0.12, 0.15]:
print(f"NPV at {rate:.0%}: ${npv(project, rate):.2f}")
Annuities and perpetuities
An annuity pays a fixed amount C at the end of each period for n periods (ordinary annuity). Its PV = C × [1 - (1+r)-n] / r. A perpetuity pays forever: PV = C / r. A growing perpetuity with growth rate g has PV = C1 / (r - g), where C1 is the first payment (one period from now) and r > g. These are closed-form shortcuts for the NPV sum. All assume end-of-period cash flows and a constant discount rate.
Scheme
; Annuity: PV = C * [1 - (1+r)^(-n)] / r
(define (annuity-pv c r n)
(* c (/ (- 1 (expt (+ 1 r) (- n))) r)))
; Perpetuity: PV = C / r (n -> infinity)
(define (perpetuity-pv c r)
(/ c r))
; $500/year for 30 years at 6%
(display "Annuity PV ($500/yr, 30yr, 6%): $")
(display (round (annuity-pv 5000.0630)))
(newline)
; $500/year forever at 6%
(display "Perpetuity PV ($500/yr, 6%): $")
(display (round (perpetuity-pv 5000.06)))
(newline)
; Growing perpetuity: PV = C1 / (r - g), where C1 is first payment, r > g
(define (growing-perpetuity-pv c1 r g)
(/ c1 (- r g)))
; C1 = $500 is the first payment (one period from now)
(display "Growing perpetuity (C1=$500, 6%, 2% growth): $")
(display (round (growing-perpetuity-pv 5000.060.02)))
Python
# Annuities and perpetuitiesdef annuity_pv(c, r, n):
return c * (1 - (1 + r) ** -n) / r
def perpetuity_pv(c, r):
return c / r
def growing_perpetuity_pv(c1, r, g):
"""c1 = first payment (one period from now), requires r > g"""return c1 / (r - g)
print(f"Annuity PV ($500/yr, 30yr, 6%): ${annuity_pv(500, 0.06, 30):.2f}")
print(f"Perpetuity PV ($500/yr, 6%): ${perpetuity_pv(500, 0.06):.2f}")
print(f"Growing perpetuity (C1=$500, 6%, 2% growth): ${growing_perpetuity_pv(500, 0.06, 0.02):.2f}")
Notation reference
Symbol
Scheme
Python
Meaning
PV
(present-value fv r n)
present_value(fv, r, n)
Present value
FV
(future-value pv r n)
future_value(pv, r, n)
Future value
r
0.05
0.05
Discount / interest rate
n
10
10
Number of periods
NPV
(npv cashflows r)
npv(cashflows, r)
Net present value
Neighbors
∫ Calculus Ch.1 — exponential and logarithmic functions power compound interest
📈 Finance Ch.2 — bond pricing applies TVM to fixed coupon streams