jape
jape

Reputation: 2901

Python function to approximate mathematical value of e

I am writing a function to approximate the mathematical value of e.

We are told to use the factorial function and the inverse function above. It is also suggested to use map.

I have this so far, but it gives me an error saying: ValueError: factorial() only accepts integral values.

def inverse(n):
    """Returns the inverse of n"""
    return 1 / n

def e(n):
    """Approximates the mathematical value e"""
    lst = range(1, n+1)
    lst2 = map(inverse, lst)
    lst3 = map(math.factorial, lst2)
    return sum(lst3)

Could someone point me in the right direction please?

Upvotes: 0

Views: 3434

Answers (4)

DainDwarf
DainDwarf

Reputation: 1669

I has some fun with that question, using generators and decorators. First, you can create a generator to yield consecutively more precise values of e:

def compute_e():
    currentFactorial = 1
    currentSum = 1
    for i in itertools.count(start=1):
        currentFactorial *= i
        currentSum += 1/currentFactorial
        yield currentSum

And, after that, I create a decorator to find a fixed point (with a maximum number of iterations, and wanted precision) :

def getFixedPoint(gen, maxiter=10000, precision=0):
    def mywrap(*args, **kwargs):
        instanceGen = gen(*args, **kwargs)
        prevValue = next(instanceGen)
        for n, value in enumerate(instanceGen):
            if (value - prevValue < precision) or (n > maxiter):
                return value
            else:
                prevValue = value
    return mywrap

which gives me stuff like this:

In [83]: getFixedPoint(compute_e)()
Out[83]: 2.7182818284590455

In [84]: getFixedPoint(compute_e, maxiter=5)()
Out[84]: 2.71827876984127

In [85]: getFixedPoint(compute_e, precision = 0.001)()
Out[85]: 2.7182539682539684

Of cours, now I can change my way of computing each successive value of e, for example by using from decimal import Decimal:

@getFixedPoint
def compute_e():
    currentFactorial = Decimal(1)
    currentSum = Decimal(1)
    for i in itertools.count(start=1):
        currentFactorial *= i
        currentSum += 1/currentFactorial
        yield currentSum

compute_e()
Out[95]: Decimal('2.718281828459045235360287474')

Upvotes: 0

R. Max
R. Max

Reputation: 6710

As everyone else pointed out:

  • You are missing the first term in the series which is 1.
  • In python, the division gives you an integer value if both numbers are integers. i.e. 1/2 == 0.

You need something like this:

def inverse(n):
    """Returns the inverse of n"""
    # Using 1 as a float makes the division return a float value.
    return 1. / n

def e(n):
    """Approximates the mathematical value e"""
    lst = range(1, n+1) # k=1...n
    lst2 = map(math.factorial, lst)
    return 1 + sum(map(inverse, lst2))

You can compare your approximation against math.exp:

>>> abs(math.exp(1) - e(20)) < 1e-10
True

Upvotes: 0

jape
jape

Reputation: 2901

This is now working for me. I needed to change the range from (1, n+1) to (0, n+1) and reverse the order of doing the factorial first and then doing the inverse.

def inverse(n):
    """Returns the inverse of n"""
    return 1 / n


def e(n):
    """Approximates the mathematical value e"""
    lst = map(math.factorial, range(0, n+1))
    return sum(map(inverse, lst))

Upvotes: 1

John Sensebe
John Sensebe

Reputation: 1396

e can be defined by Σ(1/k!), where k = 0 .. ∞.

So, for each k,

  1. compute k!
  2. invert
  3. add to total

It looks like you're doing the inversion before the factorial instead of after, and starting from 1 instead of 0.

Note that this is not the most efficient way of doing this computation, as the factorial is unnecessarily being computed from scratch for each k.

Upvotes: 1

Related Questions