Introduction
Let’s use numerical methods to solve a simple financial engineering problem. We will model an investment account into which you make regular payments, such as a retirement account or college savings fund.
The Math
If the balance P in an account earns a rate of return r, and we make a regular payment p into the account, then the account balance changes according to the differential equation:
This differential equation is easily solved:
Given an initial balance, a rate of return, and a payment rate, this equation gives you the balance after a given time. With a little algebra, you can solve it for p, to tell you the payment rate you would need to achieve a given balance after a given time. Or you could solve it for t, to tell you how long you would need to save in order to achieve a given balance.
What you cannot do with algebra is turn it into an equation for r, the rate of return you earned on an investment. This is because r appears both in the argument of the exponent and outside it. But, knowing what return we have achieved is a common question, to which we would like an answer.
The Code
We can solve this problem numerically. We will simply define a function of r that measures how far the predicted final balance differs from the actual final balance:
and search for a root of this function that is a value of r that makes f(r)=0.
We will use the root-finding capabilities of the Meta.Numerics library. Just download this free numerics library, add a reference to Meta.Numerics.dll to your project, and add the appropriate using
statements.
using Meta.Numerics;
using Meta.Numerics.Functions;
Next, define the function whose roots we want as a delegate.
Function<double, double> f = delegate (double r) {
double rt = r * t;
if (Math.Abs(rt) > 1.0e-6) {
return ((P1 + p / r) * Math.Exp(rt) - (P2 + p / r));
} else {
return ((P1 + p * t - P2) + rt * (P1 + p * t / 2.0));
}
};
Notice that we treat f(r) specially near r=0. Direct application of the expression above would result in division by zero, but in fact, f(r) is perfectly well-behaved there. You can see this for yourself by expanding the exponential in a power series, the first few terms of which give our linear approximation.
Now, all that remains is to find a root of this function. Like all numerical root-finders, the Meta.Numerics library requires that you provide an initial guess (or a bracket) for the root – otherwise, how could it know which root of a multi-rooted function to find? In most cases, it is worthwhile to put some work into finding a good initial guess. But in this case, our function can be easily evaluated everywhere, has only a single root, and has a simple, monotonic shape – this is really unnecessary. We will simply start the root-finder at r=0.
double rate = FunctionMath.FindZero(f, 0.0);
That’s it! We have solved a transcendental equation with a delegate definition and a method invocation.
More to Know
The algorithms behind the FindZero
function are fairly complicated. After all, it needs to handle arbitrary functions, without derivative information, with as few function evaluations as possible. If you need an easy-to-use, robust, efficient root-finder and don’t want to worry about the underlying algorithmic details, it’s a great choice. And, if you do want to worry about the underlying algorithmic details, the Meta.Numerics sources are available for your perusal.
If you don’t want or need to solve transcendental equations in code, but you do want or need to model account balances, you can just use this online calculator, which uses the Meta.Numerics library under the hood.