Domanda

Given inputs of:

present value = 11, SUMMATIONS of future values that = 126, and n = 7 (periods of change)

how can I solve for a rate of chain that would create a chain that sums into being the FV? This is different from just solving for a rate of return between 11 and 126. This is solving for the rate of return that allows the summation to 126. Ive been trying different ideas and looking up IRR and NPV functions but the summation aspect is stumping me.

In case the summation aspect isn't clear, if I assume a rate of 1.1, that would turn PV = 11 into a list like so (that adds up to nearly the FV 126), how can I solve for r only knowing n, summation fv and pv?:

11
12.1
13.31
14.641
16.1051
17.71561
19.487171
21.4358881

total = 125.7947691

Thank you.

EDIT: I attempted to create a sort of iterator, but it's hanging after the first loop...

for r in (1.01,1.02,1.03,1.04,1.05,1.06,1.07,1.08,1.09,1.10,1.11,1.12):
    print r
    test = round(11* (1-r**8) / (1 - r),0)
    print test
    while True:
        if round(126,0) == round(11* (1-r**8) / (1 - r),0):
            answer = r
            break
        else:
            pass

EDIT 2:

IV = float(11)
SV = float(126)
N = 8
# sum of a geometric series: (SV = IV * (1 - r^n) / (1 - r )
# r^n - (SV/PV)*r + ((SV - IV)/IV) = 0
# long form polynomial to be solved, with an n of 3 for example:
# 1r^n + 0r^n + 0r^n + -(SV/PV)r + ((SV - IV)/IV)
# each polynomial coefficient can go into numpy.roots to solve
# for the r that solves for the abcd * R = 0 above.

import numpy
array = numpy.roots([1.,0.,0.,0.,0.,0.,0.,(-SV)/IV,(SV-IV)/IV])
for i in array:
    if i > 1:
        a = str(i)
        b = a.split("+")
        answer = float(b[0])
print answer

I'm getting a ValueError that my string "1.10044876702" cant be converted to float. any ideas?

SOLVED: i.real gets the real part of it. no need for split or string conversion ie:

for i in array:
        if i > 1:
            a = i.real
            answer = float(a)
    print answer
È stato utile?

Soluzione

Sum of a geometric series

Subbing in,

126 = 11 * (1 - r**8) / (1 - r)

where we need to solve for r. After rearranging,

r**8 - (126/11)*r + (115/11) = 0

then using NumPy

import numpy as np
np.roots([1., 0., 0., 0., 0., 0., 0., -126./11, 115./11])

gives

array([-1.37597528+0.62438671j, -1.37597528-0.62438671j,
   -0.42293755+1.41183514j, -0.42293755-1.41183514j,
    0.74868844+1.1640769j ,  0.74868844-1.1640769j ,
    1.10044877+0.j        ,  1.00000000+0.j        ])

where the first six roots are imaginary and the last is invalid (gives a div-by-0 in the original equation), so the only useable answer is r = 1.10044877.

Edit:

Per the Numpy docs, np.root expects an array-like object (aka a list) containing the polynomial coefficients. So the parameters above can be read as 1.0*r^8 + 0.*r^7 + 0.*r^6 + 0.*r^5 + 0.*r^4 + 0.*r^3 + 0.*r^2 + -126./11*r + 115./11, which is the polynomial to be solved.

Your iterative solver is pretty crude; it will get you a ballpark answer, but the calculation time is exponential with the desired degree of accuracy. We can do much better!

No general analytic solution is known for an eighth-order equation, so some numeric method is needed.

If you really want to code your own solver from scratch, the simplest is Newton-Raphson method - start with a guess, then iteratively evaluate the function and offset your guess by the error divided by the first derivative to hopefully converge on a root - and hope that your initial guess is a good one and your equation has real roots.

If you care more about getting good answers quickly, np.root is hard to beat - it computes the eigenvectors of the companion matrix to simultaneously find all roots, both real and complex.

Edit 2:

Your iterative solver is hanging because of your while True clause - r never changes in the loop, so you will never break. Also, else: pass is redundant and can be removed.

After a good bit of rearranging, your code becomes:

import numpy as np

def iterative_test(rng, fn, goal):
    return min(rng, key=lambda x: abs(goal - fn(x)))

rng  = np.arange(1.01, 1.20, 0.01)
fn   = lambda x: 11. * (1. - x**8) / (1. - x)
goal = 126.
sol  = iterative_test(rng, fn, goal)

print('Solution: {} -> {}'.format(sol, fn(sol)))

which results in

Solution: 1.1 -> 125.7947691

Edit 3:

Your last solution is looking much better, but you must keep in mind that the degree of the polynomial (and hence the length of the array passed to np.roots) changes as the number of periods changes.

import numpy as np

def find_rate(present_value, final_sum, periods):
    """
    Given the initial value, sum, and number of periods in
    a geometric series, solve for the rate of growth.
    """
    # The formula for the sum of a geometric series is
    #     final_sum = sum_i[0..periods](present_value * rate**i)
    # which can be reduced to
    #     final_sum = present_value * (1 - rate**(periods+1) / (1 - rate)
    # and then rearranged as
    #     rate**(periods+1) - (final_sum / present_value)*rate + (final_sum / present_value - 1) = 0

    # Build the polynomial
    poly     = [0.] * (periods + 2)
    poly[ 0] =  1.
    poly[-2] = -1. * final_sum / present_value
    poly[-1] =  1. * final_sum / present_value - 1.

    # Find the roots
    roots = np.roots(poly)

    # Discard unusable roots
    roots = [rt for rt in roots if rt.imag == 0. and rt.real != 1.]

    # Should be zero or one roots left
    if len(roots):
        return roots[0].real
    else:
        raise ValueError('no solution found')

def main():
    pv, fs, p = 11., 126., 7
    print('Solution for present_value = {}, final_sum = {}, periods = {}:'.format(pv, fs, p))
    print('rate = {}'.format(find_rate(pv, fs, p)))

if __name__=="__main__":
    main()

This produces:

Solution for present_value = 11.0, final_sum = 126.0, periods = 7:
rate = 1.10044876702

Altri suggerimenti

Solving the polynomial roots is overkill. This computation is usually made with a solver such as the Newton method directly applied to the exponential formula. Works for fractional durations too.

For example, https://math.stackexchange.com/questions/502976/newtons-method-annuity-due-equation

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top