0
$\begingroup$

While working on some formulas, I was trying to solve for each variable. The first set of formulas deal with interest that gets calculated once per year and are fairly simple to come up with:

n = lambda iy, pv, fv: math.log(fv / pv) / math.log(iy + 1)
iy = lambda n, pv, fv: (fv / pv) ** (1 / n) - 1
pv = lambda n, iy, fv: fv / (iy + 1) ** n
fv = lambda n, iy, pv: pv * (iy + 1) ** n

The second set of formulas add a fifth variable called A that denotes how many times per year the interest gets calculated. Twelve would be a reason number for interest calculated once per month:

n = lambda iy, pv, fv, a: math.log(fv / pv) / (math.log(iy / a + 1) * a)
iy = lambda n, pv, fv, a: ((fv / pv) ** (1 / (n * a)) - 1) * a
pv = lambda n, iy, fv, a: fv / (iy / a + 1) ** (n * a)
fv = lambda n, iy, pv, a: pv * (iy / a + 1) ** (n * a)

While trying to solve for A, I came up with the following formula but do not know how to solve it:

A * log(IY / A + 1) = log(FV / PV) / N

My problem is that I am not sure how to get the values out of the logon the left side. What is A?

The process for getting the current formula was as follows:

FV = PV * (IY / A + 1) ** (N * A)
FV / PV = (IY / A + 1) ** (N * A)
N * A = log(FV / PV) / log(IY / A + 1)
A * log(IY / A + 1) = log(FV / PV) / N

Addendum 1:

After some more work with the formula, the following was developed, but the results do not appear to be helpful. While solving for the other A, the first that was practically extracted got buried:

log(IY / A + 1) = log(FV / PV) / (N * A)
IY / A + 1 = e ** (log(FV / PV) / (N * A))
IY / A = e ** (log(FV / PV) / (N * A)) - 1
A = IY / (e ** (log(FV / PV) / (N * A)) - 1)

Addendum 2:

Reading through Claude Leibovici's answer led me further down the path of trying to solve for A in the forumulas up above. From the first attempt to solve, the result became much simpler indeed:

log(IY / A + 1) = log(FV / PV) / (IY * N) * (IY / A)
b = -log(FV / PV) / (IY * N)
IY / A = W(b * e ** b) / b - 1
A = IY / (W(b * e ** b) / b - 1)
A = IY / (W(b * e ** b) / b - b / b)
A = IY / ((W(b * e ** b) - b) / b)
A = (IY * b) / (W(b * e ** b) - b)

From this formula, some code may be written in an attempt to duplicate the method needed to solve for A. Unfortunately, the resulting answer is a large, negative number but should be twelve:

#! /usr/bin/env python3
import math


def main():
    var_n = 35      # thirty-five year investment
    var_iy = .04    # four percent interest per year
    var_pv = 30000  # thirty thousand dollar investment
    var_a = 12      # compounded twelve times per year
    var_fv = round(fv(var_n, var_iy, var_pv, var_a), 2)
    print('Future Value        =', var_fv)
    var_a = a(var_n, var_iy, var_pv, var_fv)
    print('Compounded Per Year =', var_a)


fv = lambda n, iy, pv, a: pv * (iy / a + 1) ** (n * a)


def a(n, iy, pv, fv):
    b = -math.log(fv / pv) / (iy * n)
    return (iy * b) / (lambert_w(b * math.exp(b)) - b)


def lambert_w(z, tolerance=1e-8):
    a = z
    while True:
        b = math.exp(a)
        c = a * b
        d = a - (c - z) / (c + b)
        if abs(a - d) <= tolerance:
            return a
        a = d


if __name__ == '__main__':
    main()

Question: Can someone identify my mistake and help to correct the formulas shown above?

$\endgroup$
  • $\begingroup$ Think about Lambert function; there is an explicit solution for $A \log(\frac b A +1)=c$ $\endgroup$ – Claude Leibovici Oct 18 '16 at 18:02
  • $\begingroup$ @ClaudeLeibovici It's not clear to me that the Lambert W can be applied here. Even if it can, in this case it is probably easier to solve the problem numerically. $\endgroup$ – Harald Hanche-Olsen Oct 18 '16 at 18:04
  • $\begingroup$ @HaraldHanche-Olsen. Yes, it works ! The formula is more than likely awful but there is one. $\endgroup$ – Claude Leibovici Oct 18 '16 at 18:07
  • $\begingroup$ @HaraldHanche-Olsen : define $x=\frac 1A$ which makes $c x=\log(1+bx)$ $\endgroup$ – Claude Leibovici Oct 18 '16 at 18:32
  • $\begingroup$ @ClaudeLeibovici I am not familiar with the transformations that the Lambert function would require for solving the problem. Would you mind showing me what you mean? My hope is that A can be solved using functions that would be included in most programming languages. $\endgroup$ – Noctis Skytower Oct 18 '16 at 19:02
1
$\begingroup$

The equation being $$A \log\left(\frac{IY} A+1\right) =\frac 1 N \log\left(\frac{FV}{PV}\right)$$ let us define $$x =\frac{IY} A \qquad \text {and}\qquad b=\frac{\log \left(\frac{\text{FV}}{\text{PV}}\right)}{\text{IY} \times N}$$ wich makes the equation to be $$\log(1+x)=b x$$ for which Lambert function is obviously a good candidate.

In term of Lambert function, the solution then simply write

$$x=-1-\frac{W\left(-b e^{-b}\right)}{b}$$

This function is available in many softwares and you could find many subroutines (code source) in a lot of places on the Internet. In the worst case, the link provides series expansion for an evaluation of $W(z)$. If you want to code it, I suggest the iterative Halley method as proposed by Corless (look at the end of the Wikipedia page).

Otherwise, numerical solutions are quite easy considering that we look for the zero of $$f(x)=\log(1+x)-b x\qquad\text{with}\qquad f'(x)=\frac{1}{x+1}-b \qquad\text{and}\qquad f''(x)=-\frac{1}{(x+1)^2}$$ The first derivative cancels at $$x_*=\frac{1-b}{b}\implies f(x_*)=b-1-\log(b)\implies f''(x_*)<0$$

Since $x=0$ is a trivial solution, you will need to start iterating using $x_0>x_*$ (if $b>0$) or $x_0<x_*$ (if $b<0$) in order to ensure convergence to the non trivial solution (by Darboux, there will be an overshoot of the solution if you choose as a starting point $x_0$ such that $f(x_0)>0$ but it will be the unique one).

Using Newton method, the iterates will be given by

$$x_{n+1}=\frac{(x_n+1) \log (x_n+1)-x_n}{b x_n+(b-1)}$$

For illustration purposes, let us use $b=0.05$; the maximum being at $x=19$, let us start iterating at $x_0=38$. Newton method will generate the following iterates $$\left( \begin{array}{cc} n & x_n \\ 0 & 38 \\ 1 & 110.399 \\ 2 & 90.7313 \\ 3 & 90.2786 \\ 4 & 90.2783 \end{array} \right)$$

$\endgroup$
  • $\begingroup$ Thank you for your help! If you check the question's second addendum, you will find that I must have misunderstood you somewhere. The answer that is being printed for "Compounded Per Year" is -19349363.130913414 but should be close to 12 instead. $\endgroup$ – Noctis Skytower Oct 19 '16 at 18:59

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.