Saving For Retirement

I got an email a couple of months ago from a coworker about saving for retirement that included the following graph:

Being very interested in retiring someday, I wrote a quick python script to calculate retirement:

def retire(principal, num_years, rate):
    final_sum = 0
    for year in range(num_years):
        final_sum += principal
        final_sum += (final_sum * rate)
    return final_sum

Running it yields the expected values:

retire(1000, 65 - 25, .07)
Out[2]: 213609.56982787763

retire(1000, 65 - 35, .07)
Out[3]: 101073.04136640529

What happens if I increase the principal? For kicks, let's increase it to 10000.

retire(10000, 65 - 25, .07)
Out[4]: 2136095.698278777
retire(10000, 65 - 35, .07)
Out[5]: 1010730.4136640532

These are multiples of 10 from the original. When we multiply the principal by 10, the final sum is also multiplied by 10. This becomes obvious when using the math formula for it:

For the following math, P is the principal, the amount we start off with and invest every year, n is the number of years, r is the interest rate, R = 1 + r, and S_n is the sum for year n

For the first year:

$$S_1 = P + Pr = PR$$

Continuing on:

$$S_2 = (S_1 + P)R = PR^2 + PR$$

$$S_3 = (S_2 + P)R = (PR^2 + PR + P)R = PR^3 + PR^2 + PR$$

... And we can easily see a pattern for any year:

$$S_n = PR + PR^2 + ... +PR^{n-1} + PR^n$$

$$S_n = P(R + R^2 + ... + R^n)$$

$$S_n = P\sum_{1}^{n}R^n$$

So, as we can see, P really does simply multiply against the rate. That sum is known as a geometric series, and we can reduce it to the following formula:


So our formula becomes:

$$S_n = P\frac{R^{n+1}-R}{R-1}$$

Finally, let's put back our r for comparison purposes:

$$S_n = P\frac{(1+r)^{n+1}-1-r}{r}$$

This is easily placed into Python:

def retire_math(principal, num_years, rate):
    return principal * ((1 + rate)**(num_years + 1) - rate - 1) / rate

and easily tested:

retire_math(1000, 65 - 25, .07)
Out[14]: 213609.56982787818

retire_math(1000, 65-35, .07)
Out[15]: 101073.04136640551

There are differences between the two methods way after the decimal place, but those are occurring because of floating point rounding errors.

From a programming perspective, retire_math (O(constant) time) should be a lot faster than retire (O(n) time), but it is a lot less readable as well. For our use case it doesn't matter because both versions are fast enough.

retire_math also suffers in that it's input rate cannot be 0, but retire can have a 0 input.

I'm out of time, but I want to look more at and expand this function. Some things I'd like to play with:

  • Graphing it
  • Seeing which input it's most 'sensitive' too. For example, if you can either increase the interest rate by .001, or increase your principal by $1000, which should you choose? (I think partial derivatives will come in handy here)
  • extending it:
    • decrease/increase contributions over the years
    • decouple principal from contributions
    • Model leaving it alone for several years, then taking yearly sums out at a constant rate