cat brain.log | less

Getting it down on `paper`

Log Math, Compound Interest, and the Geometric Series

Compute the value of a $1000 deposit after 10 years, earning 1.5% APR, compounded monthly.

Naive:

function interest($initial=1000,$apr=0.015,$years=10) {
  $rate = $apr/12;
  $periods = 12*$years;
  $sum = $initial;
  for($i=0; $i<$periods;$i++) {
    $sum = $sum + $sum * $rate;
  }
  return $sum;
}

Log style:

function interest($initial=1000,$apr=0.015,$years=10) {
  $rate = $apr/12;
  $periods = 12*$years;
  return $initial * pow(1 + $rate, $periods);
}

Watch the boundary conditions. The above assumes the compounding occurs 12 times. Note that this log approach would not be appropriate if we were to add money to the fund after the compounding began. If the amount added per compounding period were consistent, we could devise a new log scheme.

Naive with additions:

function interest($initial=1000,$addition=100,$apr=0.015,$years=10) {
  $rate = $apr/12;
  $periods = 12*$years;
  $sum = $initial;
  for($i=0; $i<$periods; $i++) { 
    // Add interest earned in previous term.
    // Add $addition in preparation for next compounding period.
    $sum = $sum + $sum*$rate + $addition;
  }
  // Remove last $addition because there is no addition at the end-of-term.
  return $sum - $addition;
}

Log (via Geometric Series) with additions:

/**
 * Compute the balance on an account after some period of time.
 * The account may receive an initial deposit and/or regular deposits
 * at the start of every compounding period, after the first.
 * The APR, duration, and number of compounding periods may be specified.
 *
 * @see http://en.wikipedia.org/wiki/Geometric_series
 * @param float $inital Initial deposit amount
 * @param float $addition Amount added at start of each compounding period
 * @param float $apr Annual percentage rate (percent/100) earned on balance
 * @param float $years Number of years ($years>0) to compute interest for.
 * @param uint $ppyr Number of compounding periods per year.
 * @return float Balance after $years time accruing interest at $apr rate.
 */
function interest($initial=1000,$addition=100,$apr=0.015,$years=10,$ppyr=12) {
  // Use geometric series to calculate the cumulative rate of return
  // with recurring, inter-period deposits (periods 0..N-1)
  // $initial is initial deposit, interest accrues immediately.
  // $rate is interest earned per period (percent/100).
  // $addition is amount added at beginning of period after first period.
 
  // Over time, interest accrues on the additional deposits:
  // let R = (1 + rate)
  // v0 = 0  -- we'll deal with the initial deposit elsewhere.
  // v1 = v0 * R + additional
  // v2 = (v1) * R + additional
  // v2 = (v0 * R + add) * R + add
  // v2 = 0 + add*R + add
  // v2 = add*R + add
  // v3 = v2 * R + add
  // v3 = (add*R + add)*R + add
  // v3 = add(R^2 + R + 1)
  // v4 = v3 * R + add
  // v4 = (add*R*R + add*R + add)*R + add
  // v4 = add(R^3+R^2+R^1+R^0)
  // v5 = v4 * R + add
  // v5 = (v3 * R + add) * R + add
  // v5 = ((v2 * R + add) * R + add) * R + add
  // v5 = (((v1 * R + add) * R + add) * R + add) * R + add
  // v5 = ((((v0 * R + add) * R + add) * R + add) * R + add) * R + add
  // v5 = add * (R^4 + R^3 + R^2 + R^1 + R^0)
  // ... using geometric series ... a = add, r = (1+rate)
  // vN = a * (1 - pow(r,N)) / (1-r)
 
  $rate = $apr / $ppyr;
  $periods = $years * $ppyr;
 
  // Geometric series:
  // a + ar + ar^2 + ar^3 + ... + ar^n 
  //   = sum(k=0..n)[ar^k]
  //   = a * (1-r^(n+1)) / (1-r)
  // Where:
  //   a = $addition
  //   r = 1 + $rate
  //   n = $periods - 1
  //   k = [0..n]
  $a = $addition;
  $r = 1 + $rate;
  // Compute series from first period to last period
  $geom = $a * (1 - pow($r,$periods)) / (1-$r);
  // Remove $add from last period because next period didn't begin yet.
  $additional = $geom - $addition;
 
  // Compute interest on initial deposit + additional interest from above.
  return $initial * pow(1+$rate,$periods) + $additional;
}

Same as above, but without all those comments:

function interest($initial=1000,$addition=100,$apr=0.015,$years=10,$ppyr=12) {
  $R = 1 + $apr / $ppyr;
  $pow = pow( $R, $years * $ppyr );
  return ($initial * $pow) + ($addition * (1 - $pow) / (1-$R) - $addition);
}
 

Comments

No comments so far.

(comments are closed)